Disclaimer: The purpose of the Open Case Studies project is to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data. A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given data set, and should not be used in the context of making policy decisions without external consultation from scientific experts.

This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 (CC BY-NC 3.0) United States License.

To cite this case study please use:

Wright, Carrie, and Ontiveros, Michael and Jager, Leah and Taub, Margaret and Hicks, Stephanie. (2020). https://github.com/opencasestudies/ocs-bp-RTC-analysis. Influence of Multicollinearity on Measured Impact of Right-to-Carry Gun Laws (Version v1.0.0).

Motivation


This case study will introduce the topic of multicollinearity, which occurs in regression when one or more independent variable can be predicted by other independent varaibles.

We will do so by showcasing a real world example where multicollinearity in part resulted in historically controversial and conflicting findings about the influence of the adoption of right-to-carry (RTC) concealed handgun laws on violent crime rates in the United States.

We will focus on two articles:

  1. The first analysis by Mustard and Lott published in 1996 suggests that RTC laws reduce violent crime. Lott authored a book extending these findings in 1998 called More Guns, Less Crime.

[source]
  1. The second analysis is a recent article by Donohue, et al. published in 2017 that suggests that RTC laws increase violent crime. Donohue has also published previous articles with titles such as Shooting down the “More Guns, Less Crime” Hypothesis.

[source]

This has been a controversial topic as many other articles also had conflicting results. See here for a list of studies.

The Donohue, et al. article discusses how there are many other important methodological aspects besides multicollinearity (which occurs when independent varaibles are highly related in a regression analysis) that could account for the historically conflicting results in these previous papers.

In fact, nearly every aspect of the data analysis process was different between the Donohue, et al. analysis and the Mustard and Lott analysis.

AVOCADO: I like the graphic! Should we mention this process is actually investigating the replicability (e.g. this paper https://www.nature.com/articles/s41562-019-0629-z) of the study as starting with the data are different?

However, we will focus particularly on multicollinearity and how it can influence the results we get from linear regression. Specifically, this analysis will demonstrate how methodological details can be critically influential for our overall conclusions and can result in important policy related consequences. The Donohue, et al. article will provide a basis for the motivation.

John J. Donohue et al., Right‐to‐Carry Laws and Violent Crime: A Comprehensive Assessment Using Panel Data and a State‐Level Synthetic Control Analysis. Journal of Empirical Legal Studies, 16,2 (2019).

David B. Mustard & John Lott. Crime, Deterrence, and Right-to-Carry Concealed Handguns. Coase-Sandor Institute for Law & Economics Working Paper No. 41, (1996).

Before we leave this section, we provide a high-level overview of what variables were (or were not) included in the Donohue, Aneja and Weber) (DAW) paper and the Mustard and Lott (ML) paper:

[source]
*ML is abbreviated as LM in the source article

Note: We are not attempting to re-create the analyses from the original authors. Instead, we aim to use a subset of the listed explanatory variables in this case study to demonstrate multicollinearity. These variables will be consistent for both analyses that we will perform, with the exception that one analysis will have 6 demographic variables like the analysis in the Donohue, et al. article and the other will have 36 demographic variables like the analysis in the Mustard and Lott article.

Main Question


Our main question:

What is the effect of multicollinearity on linear regression models when analyzing right to carry laws and violence rates?

Specifically, we will consider the two ways to define the demographic variables (as described above) and investigate how the inclusion of different numbers of age groups influence the results of an analysis of right to carry laws and violence rates.

Learning Objectives


Statistical Learning Objectives:

  1. What multicollinearity is and how it can influence linear regression coefficients?
  2. How to look for the presence of multicollinarity and determine the severity?
  3. The difference between multicollinearity and correlation.
  4. Implementation of panel regression analysis (plm).
  5. Calculation of VIF (car).

Data science Learning Objectives:

  1. Data import of many different file types with special cases (readr, readxl, pdftools).
  2. Joining data from multiple sources (dplyr).
  3. Working with character strings (stringr).
  4. Data comparisons (dplyr and janitor).
  5. Reshaping data into different formats (tidyr).
  6. Data visualizations (ggplot2).
  7. Sampling subsets of data (rsample).

We will especially focus on using packages and functions from the tidyverse, such as dplyr and ggplot2. The tidyverse is a library of packages created by RStudio. While some students may be familiar with previous R programming packages, these packages make data science in R especially efficient.

Context


So what exactly is a right-to-carry law?

It is a law that specifies if and how citizens are allowed to have a firearm on their person or nearby (for example, in a citizen’s car) in public.

The Second Amendment to the United States Constitution guarantees the right to “keep and bear arms”. The amendment was ratified in 1791 as part of the Bill of Rights.

[source]

However, there are no federal laws about carrying firearms in public.

These laws are created and enforced at the US state level. States vary greatly in their laws about the right to carry firearms. Some require extensive effort to obtain a permit to legally carry a firearm, while other states require very minimal effort to legally carry a firearm.

Click here for more information on history of right-to-carry policies in the US.

According to Wikipedia about the history of right-to-carry policies in the United States:

Public perception on concealed carry vs open carry has largely flipped. In the early days of the United States, open carrying of firearms, long guns and revolvers was a common and well-accepted practice. Seeing guns carried openly was not considered to be any cause for alarm. Therefore, anyone who would carry a firearm but attempt to conceal it was considered to have something to hide, and presumed to be a criminal. For this reason, concealed carry was denounced as a detestable practice in the early days of the United States.

Concealed weapons bans were passed in Kentucky and Louisiana in 1813. (In those days open carry of weapons for self-defense was considered acceptable; concealed carry was denounced as the practice of criminals.) By 1859, Indiana, Tennessee, Virginia, Alabama, and Ohio had followed suit. By the end of the nineteenth century, similar laws were passed in places such as Texas, Florida, and Oklahoma, which protected some gun rights in their state constitutions. Before the mid 1900s, most U.S. states had passed concealed carry laws rather than banning weapons completely. Until the late 1990s, many Southern states were either “No-Issue” or “Restrictive May-Issue”. Since then, these states have largely enacted “Shall-Issue” licensing laws, with numerous states legalizing “Unrestricted concealed carry”.

There are five broad categories of right-to-carry laws:

[source]

You can see that no state in the US currently has a “Rights Infringed/Non-Issue” law (the gray category) – meaning that all 50 states in the US allow the right to carry firearms at least in some way. However the level of restrictions is dramatically different from one state to another.

AVOCADO: I put this next section in a details clickable box. My sense is that we should delete this information entirely from the case study, but keeping it for now and will come back and decide at the end if we want to keep it after I look through the whole thing.

Click here for more information on right-to-carry policies over time.

Here, you can see how these laws have changed over time around the country:

There is variation from state to state even within the same general category:

For example here are the current carry laws in Idaho which is considered an “Unrestricted - no permit required” state:

Idaho permits the open carrying of firearms.

Idaho law permits both residents and non-residents who are at least 18 years old to carry concealed weapons, without a carry license, outside the limits of or confines of any city, provided the person is not otherwise disqualified from being issued a license to carry.

A person may also carry concealed weapons on or about his or her person, without a license, in the person’s own place of abode or fixed place of business, on property in which the person has any ownership or leasehold interest, or on private property where the person has permission to carry from any person who has an ownership or leasehold interest in that property.

State law also allows any resident of Idaho or a current member of the armed forces of the United States to carry a concealed handgun without a license to carry, provided the person is over 18 years old and not disqualified from being issued a license to carry concealed weapons under state law. An amendment to state law that takes effect on July 1, 2020 changes the reference in the above law from “a resident of Idaho” to “any citizen of the United States.”

And here are the current carry laws in Arizona which is also considered an “Unrestricted - no permit required” state:

Arizona respects the right of law abiding citizens to openly carry a handgun.

Any person 21 years of age or older, who is not prohibited possessor, may carry a weapon openly or concealed without the need for a license. Any person carrying without a license must acknowledge and comply with the demands of a law enforcement officer when asked if he/she is carrying a concealed deadly weapon, if the officer has initiated an “investigation” such as a traffic stop.

Notice that citizens in Idaho only need to be 18 to carry a firearm, whereas they must be 21 in Arizona.

In contrast, here is an example of current carry laws in Maryland which is considered a “Rights Restricted-Very Limited Issue” state:

Carrying and Transportation in Vehicles It is unlawful for any person without a permit to wear or carry a handgun, openly or concealed, upon or about his person. It is also unlawful for any person to knowingly transport a handgun in any vehicle traveling on public roads, highways, waterways or airways, or upon roads or parking lots generally used by the public. This does not apply to any person wearing, carrying or transporting a handgun within the confines of real estate owned or leased by him, or on which he resides, or within the confines of a business establishment owned or leased by him.

Permit To Carry Application for a permit to carry a handgun is made to the Secretary of State Police. In addition to the printed application form, the applicant should submit a notarized letter stating the reasons why he is applying for a permit.

Limitations


There are some important considerations regarding this data analysis to keep in mind:

  1. We do not use all of the data used by either the Mustard and Lott or Donohue, et al. analyses, nor do we perform the same analysis as in each article. We instead perform a much simpler analysis with fewer variables for the purposes of illustration of the concept of multicollinearity and its influence on regression coefficients, not to reproduce either analysis.

  2. Our analysis accounts for either the adoption or lack of adoption of a permissive right-to-carry law in each state, but does not account for differences in the level of permissiveness of the laws.

Recall that these are the categories of right to carry laws:

States with laws of the category rights restricted - very limited issue (red) are considered as not having a permissive right-to-carry law. Recall that no states currently have a rights infringed/non-issue law.

States of all other categories (shall issue, discretionary/reasonable issue, and no permit required) (all shades of blue) are considered the same in our analysis, as having a permissive right-to-carry law.

  1. Because our analysis is an oversimplification, our analysis should not be used for determining policy changes, instead we suggest that users consult with a specialist.

avocado - this is from Michael and very important… not sure how we want to word this…

It is important to note that we do not treat race as an objective measure. Despite this, it can be used to advance scientific inquiry. For more information on this topic, we have included a link to a paper on the use of race as a measure in epidemiology.

We will begin by loading the packages that we will need:

Package Use
here to easily load and save data
readxl to import the data in the excel files
readr to import the CSV file data
pdftools to import data from a pdf file
dplyr to arrange/filter/select/compare specific subsets of the data
magrittr to use the compound assignment pipe operator %<>%
tidyr to rearrange data in wide and long formats
stringr to manipulate the character strings within the data
purrr to import the data in all the different excel and csv files efficiently
forcats to allow for reordering of factors in plots
tibble to create data objects that we can manipulate with dplyr/stringr/tidyr/purrr
car to calculate VIF values on linear model output
plm to work with panel data fitting fixed effects and linear regression models
broom to create nicely formatted model output
cowplot to allow plots to be combined
GGally to extend ggplot2 functionality to easily create more complex plots
ggrepel to allow labels in figures not to overlap
scales to allow us to look at the colors within the viridis package and to override some ggplot2 defaults for scales and legends
latex2exp to convert latex math formulas to R’s plotmath expressions
viridis to make plots with a color palette that is compatible with color blindness
ggcorrplot to easily visualize a correlation matrix
rsample a tidyverse package for easily resampling data

The first time we use a function, we will use the :: to indicate which package we are using. Unless we have overlapping function names, this is not necessary, but we will include it here to be informative about where the functions we will use come from.

What are the data?


Below is a table from the Donohue, et al. paper that shows the data used in both analyses, where DAW stands for Donohue, et al. and LM stands for Mustard and Lott.

We will be using a subset of these variables, which are highlighted in green:

Data Import and Wrangling


avocado:add link below

See this case study for details about data import and wrangling.

Demographic and population data

To obtain information about age, sex, and race, and overall population we will use US Census Bureau data, just like both of the articles. The census data is available for different time spans. Here are the links for the years used in our analysis. We will use data from 1977 to 2010.

Data Link
years 1977 to 1979 link
years 1980 to 1989 link * county data was used for this decade which also has state information
years 1990 to 1999 link
years 2000 to 2010 link
technical documentation

State FIPS codes

The data was downloaded from the US Census Bureau.

Police staffing data

The following data was downloaded from the Federal Bureau of Investigation.

Unemployment data

The following data was downloaded from the U.S. Bureau of Labor Statistics.

Poverty data

Extracted from Table 21 from US Census Bureau Poverty Data

Violent crime

Violent crime data was obtained from here.

Right-to-carry data

This data is extracted from table in Donohue paper {target="_blank"}.


Here is the table from the Donohue paper that compares the data used in the analyses:

[source]
*ML is abbreviated as LM in the source article

We can see that only the percentage of males that were from age 15-39 of the race groups (black, white, and other) were used in the Donohue analysis.

Ultimately we made a tibble of data that was similar to each analysis. We will load this data now, which is located in the data directory. We can use the here() function of the here package to easily locate it.

We will check the dimensions of each tibble using the base dim() function:

[1] 1395   50
[1] 1395   20

As expected the Lott_DF is 30 columns larger, due to the 30 additional demographic variables. We can check those now as well.

 [1] "YEAR"                           "STATE"                         
 [3] "Black_Female_10_to_19_years"    "Black_Female_20_to_29_years"   
 [5] "Black_Female_30_to_39_years"    "Black_Female_40_to_49_years"   
 [7] "Black_Female_50_to_64_years"    "Black_Female_65_years_and_over"
 [9] "Black_Male_10_to_19_years"      "Black_Male_20_to_29_years"     
[11] "Black_Male_30_to_39_years"      "Black_Male_40_to_49_years"     
[13] "Black_Male_50_to_64_years"      "Black_Male_65_years_and_over"  
[15] "Other_Female_10_to_19_years"    "Other_Female_20_to_29_years"   
[17] "Other_Female_30_to_39_years"    "Other_Female_40_to_49_years"   
[19] "Other_Female_50_to_64_years"    "Other_Female_65_years_and_over"
[21] "Other_Male_10_to_19_years"      "Other_Male_20_to_29_years"     
[23] "Other_Male_30_to_39_years"      "Other_Male_40_to_49_years"     
[25] "Other_Male_50_to_64_years"      "Other_Male_65_years_and_over"  
[27] "White_Female_10_to_19_years"    "White_Female_20_to_29_years"   
[29] "White_Female_30_to_39_years"    "White_Female_40_to_49_years"   
[31] "White_Female_50_to_64_years"    "White_Female_65_years_and_over"
[33] "White_Male_10_to_19_years"      "White_Male_20_to_29_years"     
[35] "White_Male_30_to_39_years"      "White_Male_40_to_49_years"     
[37] "White_Male_50_to_64_years"      "White_Male_65_years_and_over"  
[39] "Unemployment_rate"              "Poverty_rate"                  
[41] "Viol_crime_count"               "Population"                    
[43] "police_per_100k_lag"            "RTC_LAW_YEAR"                  
[45] "RTC_LAW"                        "TIME_0"                        
[47] "TIME_INF"                       "Viol_crime_rate_1k"            
[49] "Viol_crime_rate_1k_log"         "Population_log"                
 [1] "YEAR"                      "STATE"                    
 [3] "Black_Male_15_to_19_years" "Black_Male_20_to_39_years"
 [5] "Other_Male_15_to_19_years" "Other_Male_20_to_39_years"
 [7] "White_Male_15_to_19_years" "White_Male_20_to_39_years"
 [9] "Unemployment_rate"         "Poverty_rate"             
[11] "Viol_crime_count"          "Population"               
[13] "police_per_100k_lag"       "RTC_LAW_YEAR"             
[15] "RTC_LAW"                   "TIME_0"                   
[17] "TIME_INF"                  "Viol_crime_rate_1k"       
[19] "Viol_crime_rate_1k_log"    "Population_log"           

Lastly, we will check that the YEAR values are the same. We can use the setequal() function of the dplyr package to see if the values are the same.

[1] TRUE

Data Exploration


Let’s do some quick visualizations to get a sense of our outcome of interest, the violent crime data.

First we will plot the rate of violent crime over time to get a sense of the general trend.

To do so we need to summarise the data for each year across all of the states. Thus we will use the group_by() function and the summarise() functions to calculate an overall sum of violent crime relative to the population for each year.

Then we will use the ggplot2 package to plot the data. The first step in creating a plot with this package is to use the ggplot() function and the aes() argument to specify what data should be plotted on the x-axis and what data should be plotted in on the y-axis. Then we select what type of plot we would like to make using one of the geom_*() functions. Please see this case study for more details.

We can use the scale_x_continuous() and scale_y_continuous() functions to modify the axis labels.

The labs() function can be used to add labels to the plot, while the theme() function allows for manipulation of the details of the labels, like size and angle.

All of these functions are part of the ggplot2 package.

Interesting! It appears that there was an overall national peak in violent crime in the early 1990s that has since then declined.

Now let’s take a look at each state.

We will use the ggrepel package to add text to the plot using the geom_text_repel() function. This is especially useful when there is a lot of text, as this function reduces the overlap of text labels. Again see this case study for more details on how to add labels to elements of plots.

Looks like the crime rages vary quite a bit from one state to another. Some states show increased crime over time while others show decreased crime.

Now let’s take a closer look at some of our other variables.

We can also use the vis_miss() function of the naniar package to confirm that there are no missing values.

Looks like no missing data!

Same for the LOTT_DF.

We can use the skim() of the skimr package to get a better sense of the data. This also shows missingness, as well as standard deviations, spread, and means for our data. Also notice that there is a histogram of each variable.

Data summary
Name DONOHUE_DF
Number of rows 1395
Number of columns 20
_______________________
Column type frequency:
character 1
logical 1
numeric 18
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
STATE 0 1 4 20 0 45 0

Variable type: logical

skim_variable n_missing complete_rate mean count
RTC_LAW 0 1 0.37 FAL: 883, TRU: 512

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
YEAR 0 1 1995.00 8.95 1980.00 1987.00 1995.00 2003.00 2010.00 ▇▇▇▇▇
Black_Male_15_to_19_years 0 1 0.52 0.51 0.02 0.13 0.35 0.73 3.46 ▇▂▁▁▁
Black_Male_20_to_39_years 0 1 1.73 1.76 0.07 0.50 1.17 2.30 11.33 ▇▂▁▁▁
Other_Male_15_to_19_years 0 1 0.26 0.40 0.01 0.08 0.14 0.28 2.90 ▇▁▁▁▁
Other_Male_20_to_39_years 0 1 0.92 1.40 0.07 0.31 0.55 0.99 9.90 ▇▁▁▁▁
White_Male_15_to_19_years 0 1 3.09 0.72 0.55 2.69 3.14 3.54 4.99 ▁▁▇▇▁
White_Male_20_to_39_years 0 1 12.55 2.29 4.41 11.18 12.65 14.15 18.44 ▁▂▇▇▂
Unemployment_rate 0 1 6.03 2.10 2.30 4.50 5.60 7.20 17.80 ▇▇▂▁▁
Poverty_rate 0 1 13.34 3.84 5.70 10.40 12.70 15.50 27.20 ▃▇▅▁▁
Viol_crime_count 0 1 31760.77 46494.46 322.00 5107.50 14412.00 38782.50 345624.00 ▇▁▁▁▁
Population 0 1 5446810.81 6070687.33 404680.00 1363737.50 3504892.00 6411701.00 37349363.00 ▇▂▁▁▁
police_per_100k_lag 0 1 316.57 115.59 83.76 248.53 301.00 358.31 1021.14 ▅▇▁▁▁
RTC_LAW_YEAR 0 1 Inf NaN 1985.00 1995.00 1997.00 2011.00 Inf ▇▇▂▅▂
TIME_0 0 1 1980.00 0.00 1980.00 1980.00 1980.00 1980.00 1980.00 ▁▁▇▁▁
TIME_INF 0 1 2010.00 0.00 2010.00 2010.00 2010.00 2010.00 2010.00 ▁▁▇▁▁
Viol_crime_rate_1k 0 1 5.05 3.19 0.48 2.85 4.54 6.44 29.30 ▇▃▁▁▁
Viol_crime_rate_1k_log 0 1 1.45 0.60 -0.74 1.05 1.51 1.86 3.38 ▁▂▇▅▁
Population_log 0 1 14.99 1.05 12.91 14.13 15.07 15.67 17.44 ▃▅▇▅▂
Data summary
Name LOTT_DF
Number of rows 1395
Number of columns 50
_______________________
Column type frequency:
character 1
logical 1
numeric 48
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
STATE 0 1 4 20 0 45 0

Variable type: logical

skim_variable n_missing complete_rate mean count
RTC_LAW 0 1 0.37 FAL: 883, TRU: 512

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
YEAR 0 1 1995.00 8.95 1980.00 1987.00 1995.00 2003.00 2010.00 ▇▇▇▇▇
Black_Female_10_to_19_years 0 1 1.00 1.02 0.02 0.23 0.63 1.44 6.53 ▇▂▁▁▁
Black_Female_20_to_29_years 0 1 0.99 1.09 0.02 0.23 0.60 1.36 7.73 ▇▂▁▁▁
Black_Female_30_to_39_years 0 1 0.91 1.00 0.01 0.19 0.57 1.27 6.11 ▇▂▁▁▁
Black_Female_40_to_49_years 0 1 0.75 0.86 0.01 0.13 0.48 1.09 5.45 ▇▂▁▁▁
Black_Female_50_to_64_years 0 1 0.76 0.96 0.00 0.12 0.44 1.06 6.10 ▇▂▁▁▁
Black_Female_65_years_and_over 0 1 0.60 0.85 0.00 0.07 0.34 0.81 6.12 ▇▁▁▁▁
Black_Male_10_to_19_years 0 1 1.02 1.01 0.03 0.26 0.67 1.46 6.32 ▇▂▁▁▁
Black_Male_20_to_29_years 0 1 0.93 0.93 0.04 0.29 0.65 1.24 6.57 ▇▂▁▁▁
Black_Male_30_to_39_years 0 1 0.81 0.84 0.02 0.23 0.54 1.08 5.37 ▇▂▁▁▁
Black_Male_40_to_49_years 0 1 0.65 0.72 0.01 0.15 0.43 0.92 4.45 ▇▂▁▁▁
Black_Male_50_to_64_years 0 1 0.62 0.76 0.00 0.13 0.38 0.86 4.79 ▇▂▁▁▁
Black_Male_65_years_and_over 0 1 0.38 0.51 0.00 0.05 0.24 0.51 3.56 ▇▁▁▁▁
Other_Female_10_to_19_years 0 1 0.51 0.77 0.03 0.15 0.27 0.55 5.33 ▇▁▁▁▁
Other_Female_20_to_29_years 0 1 0.49 0.70 0.04 0.17 0.30 0.55 5.55 ▇▁▁▁▁
Other_Female_30_to_39_years 0 1 0.47 0.74 0.04 0.16 0.28 0.51 5.36 ▇▁▁▁▁
Other_Female_40_to_49_years 0 1 0.38 0.69 0.02 0.11 0.21 0.38 5.46 ▇▁▁▁▁
Other_Female_50_to_64_years 0 1 0.38 0.83 0.02 0.09 0.18 0.35 7.10 ▇▁▁▁▁
Other_Female_65_years_and_over 0 1 0.24 0.72 0.01 0.05 0.09 0.18 6.20 ▇▁▁▁▁
Other_Male_10_to_19_years 0 1 0.52 0.80 0.03 0.15 0.28 0.56 5.58 ▇▁▁▁▁
Other_Male_20_to_29_years 0 1 0.48 0.70 0.03 0.17 0.29 0.53 5.33 ▇▁▁▁▁
Other_Male_30_to_39_years 0 1 0.44 0.71 0.03 0.14 0.26 0.47 5.06 ▇▁▁▁▁
Other_Male_40_to_49_years 0 1 0.35 0.65 0.02 0.09 0.19 0.34 5.13 ▇▁▁▁▁
Other_Male_50_to_64_years 0 1 0.33 0.73 0.01 0.08 0.15 0.29 6.50 ▇▁▁▁▁
Other_Male_65_years_and_over 0 1 0.19 0.58 0.01 0.03 0.07 0.14 4.51 ▇▁▁▁▁
White_Female_10_to_19_years 0 1 5.72 1.38 0.94 5.01 5.82 6.61 9.45 ▁▁▇▆▁
White_Female_20_to_29_years 0 1 6.09 1.36 1.59 5.23 5.92 6.93 9.66 ▁▂▇▅▂
White_Female_30_to_39_years 0 1 6.17 1.22 1.53 5.46 6.28 7.02 8.95 ▁▁▅▇▂
White_Female_40_to_49_years 0 1 5.58 1.23 1.20 4.85 5.68 6.41 8.33 ▁▁▇▇▃
White_Female_50_to_64_years 0 1 6.56 1.45 1.72 6.01 6.57 7.34 11.40 ▁▂▇▂▁
White_Female_65_years_and_over 0 1 6.38 1.70 1.05 5.37 6.62 7.51 9.90 ▁▁▆▇▂
White_Male_10_to_19_years 0 1 6.04 1.43 1.02 5.30 6.14 6.95 9.74 ▁▁▇▇▁
White_Male_20_to_29_years 0 1 6.28 1.33 2.41 5.43 6.12 7.14 10.84 ▁▆▇▃▁
White_Male_30_to_39_years 0 1 6.27 1.19 1.93 5.59 6.33 7.06 9.67 ▁▂▇▆▁
White_Male_40_to_49_years 0 1 5.59 1.22 1.35 4.79 5.67 6.43 8.39 ▁▁▇▇▂
White_Male_50_to_64_years 0 1 6.26 1.40 1.78 5.64 6.19 6.94 10.93 ▁▂▇▂▁
White_Male_65_years_and_over 0 1 4.56 1.19 1.02 3.80 4.78 5.34 7.51 ▁▂▇▇▁
Unemployment_rate 0 1 6.03 2.10 2.30 4.50 5.60 7.20 17.80 ▇▇▂▁▁
Poverty_rate 0 1 13.34 3.84 5.70 10.40 12.70 15.50 27.20 ▃▇▅▁▁
Viol_crime_count 0 1 31760.77 46494.46 322.00 5107.50 14412.00 38782.50 345624.00 ▇▁▁▁▁
Population 0 1 5446810.81 6070687.33 404680.00 1363737.50 3504892.00 6411701.00 37349363.00 ▇▂▁▁▁
police_per_100k_lag 0 1 316.57 115.59 83.76 248.53 301.00 358.31 1021.14 ▅▇▁▁▁
RTC_LAW_YEAR 0 1 Inf NaN 1985.00 1995.00 1997.00 2011.00 Inf ▇▇▂▅▂
TIME_0 0 1 1980.00 0.00 1980.00 1980.00 1980.00 1980.00 1980.00 ▁▁▇▁▁
TIME_INF 0 1 2010.00 0.00 2010.00 2010.00 2010.00 2010.00 2010.00 ▁▁▇▁▁
Viol_crime_rate_1k 0 1 5.05 3.19 0.48 2.85 4.54 6.44 29.30 ▇▃▁▁▁
Viol_crime_rate_1k_log 0 1 1.45 0.60 -0.74 1.05 1.51 1.86 3.38 ▁▂▇▅▁
Population_log 0 1 14.99 1.05 12.91 14.13 15.07 15.67 17.44 ▃▅▇▅▂
We can see from this function, th at we have t he number of var iables of the class types that we expe ct for each t ibble. We can also see tha t the mean of the variables that should be the same for each tibble are in fact the same.
We can also tell that the values for the vari ables are in gen eral what we would expect.

Data Analysis


Donohue, et al.

OK! We are now ready to start analyzing our data!.

We have what is called panel data . This is a special type of longitudinal data. Longitudinal data are data measurements taken over time. Panel data are data repeatedly measured for for multiple panel members or individuals over time. This is in contrast with time series data, which measures one individual over time and cross sectional data, which measures multiple individuals at one point in time. In other words, panel data is a combination of both, in this case we measure multiple individuals over multiple time periods. In our case, we have measurements of violent crime and other variables for each state over many years. Therefore we are using measurements about the same states over time.

In a panel analysis there are \(N\) individual panel members and \(T\) time points.

There are two types of panels:
1. Balanced - At each time point (\(T\)), there are data points for each individual(\(N\)).

Time Points (\(T\)) Individuals (\(N\))
1977 Nevada
1977 Alabama
1977 Kansas
1978 Nevada
1978 Alabama
1978 Kansas
1979 Nevada
1979 Alabama
1979 Kansas
  1. Unbalanced - There may be data points missing for some individuals (\(N\)) at some time points (\(T\)).
Time Points (\(T\)) Individuals (\(N\))
1977 Nevada
1977 Alabama
1978 Nevada
1978 Alabama
1979 Nevada
1979 Alabama
1979 Kansas

Overall in a a balanced panel, we have \(n\) observations, where \(n = N*T\).

In an unbalanced panel, the number of observations is less than \(N*T\).

In our case we have:
\(N\) = 45 states (recall that we removed those who had adopted a RTC law before 1980)
\(T\) = 31 years (1980 - 2010)

In every year we have measurements for each state (as we just saw above), thus our panel is balanced.

So, our total observations \(n = 45*31\), thus \(n\) = 1395.

We will be performing a panel linear regression model analysis.

In such an analysis we will model our data according to this generic model:

\[Y_{it}=β_{0}+β_{1}X_{1it}+...+β_{K}X_{Kit}\]

Where \(i\) is the individual dimension (in our case individual states) and \(t\) is the time dimension.

Some explanatory/independent variables or regressors \(X_{it}\) will vary across individuals and time, while others will be fixed across the time of the study (or don’t change over time), while others still will be fixed across individuals but vary across time periods.

There are three general sub-types of panel regression analysis.

Overall, they assume that the different individuals are independent, however the same data for the same individual may be correlated across time.

The main difference between the three sub-types are the assumptions about unobserved differences between individuals.

  1. independently pooled panels - assumes that there are no individual effects that are independent of time and also no effect of time on all the individuals. In other words, the independent variables are not correlated with any error term. This is essentially an ordinary least squares linear regression. This type of panel regression makes the most assumptions and is therefore typically not used for panel data.

\[Y_{it}=\beta_{0}+\beta_{1}x_{1it}+...+\beta__KX_{Kit} + e_{it}\] Where the intercept \(\beta_0it=\beta_0\)for all \(i,t\) and slope \(\beta_kit=\beta_k\) for all \(i,t\).

  1. fixed effects - assumes that there are unknown or unobserved unique aspects about the individuals or heterogeneity among individuals \(B_0i\) that are not explained by the independent variables but influence the outcome variable of interest. They do not vary with time or in other words are fixed over time but may be correlated with independent variables \(X_{it}\).

In this case the intercept can be different for each individual \(\beta_{0i}\), but the slope is the same across all the individuals.

These individual \(a_i\) effects can be correlated with the independent variables \(X\).

\[Y_{it}=\beta_{0i}+\beta_{1}X_{1it}+...\beta_{k}X_{kit}+e_it\] This type of panel regression makes the least assumptions.

  1. random effects - assumes that there are unknown or unobserved unique qualities about the individuals that influences the outcome variable of interest that are not correlated with the independent variables.

Thus, the random effects model actually makes more assumptions than the fixed effect model.

\[Y_{it} =\beta_0 X_{it} +\beta_{1}X_{1it}+... \beta_k X_{kt} + e_{t}\] So each individual has the same slope and the same overall error term (\(\beta + e_{t}\)).

See here and here and here for more information about these different models.

We will be performing a fixed effect panel regression analysis, as we do in fact think that some of the unobserved qualities about the different states that may be correlated with some of our independent variables. For example, the level of economic opportunity might be an unobserved feature about the states that influences violent crime rate and would be possibly correlated with poverty rate and unemployment.

To perform our analysis we will be using the plm package. This stands for Panel Linear Model.

We need to use a special type of data to use this package, called a pdata.frame which is short for panel data frame. This allows us to specify that we are using panel data and what the panel structure looks like.

We need to indicate variable should be used to identify the individuals in our panel, and what variable should be used to identify the time periods in our panel. In our case the STATE variable identifies the individuals and the YEAR variable identifies the time periods.

We can specify this structure using the pdata.frame() function of the plm package, by using the index argument, where the individual variable is specified first followed by the time variable, like so: `index=c(“Individual_Variable_NAME”, “Time_Period_Variable_NAME”).

[1] "pdata.frame" "data.frame" 
            YEAR  STATE Black_Male_15_to_19_years Black_Male_20_to_39_years
Alaska-1980 1980 Alaska                 0.1670456                 0.9933775
Alaska-1981 1981 Alaska                 0.1732299                 1.0028219
Alaska-1982 1982 Alaska                 0.1737069                 1.0204445
            Other_Male_15_to_19_years Other_Male_20_to_39_years
Alaska-1980                  1.129782                  2.963329
Alaska-1981                  1.124441                  2.974775
Alaska-1982                  1.069821                  3.015071
            White_Male_15_to_19_years White_Male_20_to_39_years
Alaska-1980                  3.627805                  18.28852
Alaska-1981                  3.558261                  18.12821
Alaska-1982                  3.391844                  18.10666
            Unemployment_rate Poverty_rate Viol_crime_count Population
Alaska-1980               9.6          9.6             1919     404680
Alaska-1981               9.4          9.0             2537     418519
Alaska-1982               9.9         10.6             2732     449608
            police_per_100k_lag RTC_LAW_YEAR RTC_LAW TIME_0 TIME_INF
Alaska-1980            194.7218         1995   FALSE   1980     2010
Alaska-1981            200.2299         1995   FALSE   1980     2010
Alaska-1982            191.0553         1995   FALSE   1980     2010
            Viol_crime_rate_1k Viol_crime_rate_1k_log Population_log
Alaska-1980           4.742018               1.556463       12.91085
Alaska-1981           6.061851               1.802015       12.94448
Alaska-1982           6.076404               1.804413       13.01613

Indeed we have now created a pdata.frame object and we can see that the row names show the individual states and time period years.

OK, now we are ready to run our panel linear model on our panel data frame.

To do so we will use the plm() function and we will specify the formula for our model, where the dependent variable Viol_crime_rate_1k_log will be on the left of our ~ sign and all of the independent variables will be listed on the right with + signs in between each.

We also need to specify what type of effect we would like to model and what type of model we would like to use.

There are three main options for the effect argument: 1) individual - model for the effect of individual identity 2) time - model for the effect of time 3) twoways - meaning modeling for the effect of both individual identity and time

There are four main options for the model argument:
1) pooling - standard pooled ordinary least squares regression model
2) within - fixed effects model (variation between individuals is ignored, model compares individuals to themselves at different periods of time)
3) between - fixed effects model (variation within individuals from one time point to another is ignored, model compares different individuals at each point of time)
4) random - random effects (each state has a different intercept but force it to follow a normal distribution - requires more assumptions)

Typically it is best to think about what you are trying to evaluate with your data in trying to choose how to model your data. However, there are also some tests that can help to assess this which we will briefly cover.

We are interested in how violence in each state varied over time, thus we are interested in within STATEvariation, so we will perform our plm with the model = within argument to perform this particular type of fixed effects model.

We also speculate that there is an effect of individual STATE identity and time on violent crime rate. In other words, we expect some states to have high rates of crime, and others to have low rates of crime. We also expect crime to change over time.

If we were to perform this type of analysis we would use the effect = "twoways" argument in our plm() function like so:

To see the results we can use the base summary() function. We can view this output in tidy format using the tidy() function of the broom package.

We will add an analysis variable is a label for plots.

Twoways effects Within Model

Call:
plm(formula = Viol_crime_rate_1k_log ~ RTC_LAW + White_Male_15_to_19_years + 
    White_Male_20_to_39_years + Black_Male_15_to_19_years + Black_Male_20_to_39_years + 
    Other_Male_15_to_19_years + Other_Male_20_to_39_years + Unemployment_rate + 
    Poverty_rate + Population_log + police_per_100k_lag, data = d_panel_DONOHUE, 
    effect = "twoways", model = "within")

Balanced Panel: n = 45, T = 31, N = 1395

Residuals:
       Min.     1st Qu.      Median     3rd Qu.        Max. 
-0.57957437 -0.08942194 -0.00090654  0.08673054  1.11216999 

Coefficients:
                             Estimate  Std. Error t-value  Pr(>|t|)    
RTC_LAWTRUE                0.01796779  0.01663911  1.0799 0.2804066    
White_Male_15_to_19_years -0.00091825  0.02724210 -0.0337 0.9731160    
White_Male_20_to_39_years  0.03466473  0.00972839  3.5633 0.0003794 ***
Black_Male_15_to_19_years -0.05673593  0.05746052 -0.9874 0.3236341    
Black_Male_20_to_39_years  0.12605439  0.01931450  6.5264 9.607e-11 ***
Other_Male_15_to_19_years  0.69201638  0.11322394  6.1119 1.297e-09 ***
Other_Male_20_to_39_years -0.30276797  0.03811855 -7.9428 4.226e-15 ***
Unemployment_rate         -0.01685806  0.00489952 -3.4408 0.0005984 ***
Poverty_rate              -0.00780235  0.00295720 -2.6384 0.0084280 ** 
Population_log            -0.17991653  0.06041773 -2.9779 0.0029559 ** 
police_per_100k_lag        0.00060391  0.00013689  4.4115 1.111e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Total Sum of Squares:    43.211
Residual Sum of Squares: 36.716
R-Squared:      0.15031
Adj. R-Squared: 0.095138
F-statistic: 21.0514 on 11 and 1309 DF, p-value: < 2.22e-16
# A tibble: 11 x 7
   term                 estimate std.error statistic  p.value conf.low conf.high
   <chr>                   <dbl>     <dbl>     <dbl>    <dbl>    <dbl>     <dbl>
 1 RTC_LAWTRUE          0.0180    0.0166      1.08   2.80e- 1 -1.46e-2  0.0506  
 2 White_Male_15_to_1… -0.000918  0.0272     -0.0337 9.73e- 1 -5.43e-2  0.0525  
 3 White_Male_20_to_3…  0.0347    0.00973     3.56   3.79e- 4  1.56e-2  0.0537  
 4 Black_Male_15_to_1… -0.0567    0.0575     -0.987  3.24e- 1 -1.69e-1  0.0559  
 5 Black_Male_20_to_3…  0.126     0.0193      6.53   9.61e-11  8.82e-2  0.164   
 6 Other_Male_15_to_1…  0.692     0.113       6.11   1.30e- 9  4.70e-1  0.914   
 7 Other_Male_20_to_3… -0.303     0.0381     -7.94   4.23e-15 -3.77e-1 -0.228   
 8 Unemployment_rate   -0.0169    0.00490    -3.44   5.98e- 4 -2.65e-2 -0.00726 
 9 Poverty_rate        -0.00780   0.00296    -2.64   8.43e- 3 -1.36e-2 -0.00201 
10 Population_log      -0.180     0.0604     -2.98   2.96e- 3 -2.98e-1 -0.0615  
11 police_per_100k_lag  0.000604  0.000137    4.41   1.11e- 5  3.36e-4  0.000872

We will now perform a test to determine if we could have simply used a pooled model. This test evaluates if the coefficients (including the intercepts) are equal. To perform this test we will use the pooltest() function of the plm package to compare the pooled model to the fixed effect within model.


    F statistic

data:  Viol_crime_rate_1k_log ~ RTC_LAW + White_Male_15_to_19_years +  ...
F = 15.299, df1 = 484, df2 = 855, p-value < 2.2e-16
alternative hypothesis: unstability

The p-value is less than a significance threshold of .05, thus we reject the null that our coefficients are all equal. Thus the within fixed effects model fit the data better.

We can also perform a test to evaluate if there is indeed an individual effect and a time effect in our model.

We can use the plmtest() function of the plm package. This performs a Lagrange Multiplier Test. To do so, we need to get the output for a simple pooled model.


    Lagrange Multiplier Test - two-ways effects (Honda) for balanced
    panels

data:  Viol_crime_rate_1k_log ~ RTC_LAW + White_Male_15_to_19_years +  ...
normal = 72.56, p-value < 2.2e-16
alternative hypothesis: significant effects

Again, the p-value is much smaller than the significance threshold of < 0.05. Therefore we reject the null that there are no effects, and we can feel confident with proceeding with a twoway effect model.

There is one more test that we could perform. To test if using a random effect model would be more appropriate compared to the fixed effect model, one could use the Hausmen test for this (also called the Durbin-Wu-Hausman test). This can be implemented using the phtest() function of the plm package.


    Hausman Test

data:  Viol_crime_rate_1k_log ~ RTC_LAW + White_Male_15_to_19_years +  ...
chisq = 59.54, df = 11, p-value = 1.129e-08
alternative hypothesis: one model is inconsistent

This test evaluates if there are errors \(u_i\) that are correlated with any of the independent variables.

We reject the null hypothesis, that there are no inconsistencies, and are confirmed in our plan to used a fixed effects model.

For more information on these tests and this package, see here and here.

avocado- what do you think about referencing these slides from Princeton?

A final note about the fixed and random effects terminology and how this is slightly different than other definitions:

According to the documentation for the PLM package: >The fixed/random effects terminology in econometrics is often recognized to be misleading, as both are treated as random variates in modern econometrics (see, e.g., Wooldridge (2002) 10.2.1). It has been recognized since Mundlak’s classic paper (Mundlak (1978)) that the fundamental issue is whether the unobserved effects are correlated with the regressors or not. In this last case, they can safely be left in the error term, and the serial correlation they induce is cared for by means of appropriate GLS transformations. On the contrary, in the case of correlation, “fixed effects” methods such as least squares dummy variables or time-demeaning are needed, which explicitly, although inconsistently27, estimate a group– (or time–) invariant additional parameter for each group (or time period).

Thus, from the point of view of model specification, having fixed effects in an econometric model has the meaning of allowing the intercept to vary with group, or time, or both, while the other parameters are generally still assumed to be homogeneous. Having random effects means having a group– (or time–, or both) specific component in the error term.

In the mixed models literature, on the contrary, fixed effect indicates a parameter that is assumed constant, while random effects are parameters that vary randomly around zero according to a joint multivariate normal distribution.

Mustard and Lott

Ok, now we will do the same for the Mustard and Lott analysis. In this case we would have a very large formula to write. So instead, we can use the as.formula() function of the stats package and the base paste() function to combine all of our explanatory variables into one formula without making a mistake. First we will create an object where we select only for the explanatory variables.

avocado I tried using glue or dplyr::collapse to make this tidyverse but this didn’t work

Viol_crime_rate_1k_log ~ RTC_LAW + White_Female_10_to_19_years + 
    White_Female_20_to_29_years + White_Female_30_to_39_years + 
    White_Female_40_to_49_years + White_Female_50_to_64_years + 
    White_Female_65_years_and_over + White_Male_10_to_19_years + 
    White_Male_20_to_29_years + White_Male_30_to_39_years + White_Male_40_to_49_years + 
    White_Male_50_to_64_years + White_Male_65_years_and_over + 
    Black_Female_10_to_19_years + Black_Female_20_to_29_years + 
    Black_Female_30_to_39_years + Black_Female_40_to_49_years + 
    Black_Female_50_to_64_years + Black_Female_65_years_and_over + 
    Black_Male_10_to_19_years + Black_Male_20_to_29_years + Black_Male_30_to_39_years + 
    Black_Male_40_to_49_years + Black_Male_50_to_64_years + Black_Male_65_years_and_over + 
    Other_Female_10_to_19_years + Other_Female_20_to_29_years + 
    Other_Female_30_to_39_years + Other_Female_40_to_49_years + 
    Other_Female_50_to_64_years + Other_Female_65_years_and_over + 
    Other_Male_10_to_19_years + Other_Male_20_to_29_years + Other_Male_30_to_39_years + 
    Other_Male_40_to_49_years + Other_Male_50_to_64_years + Other_Male_65_years_and_over + 
    Unemployment_rate + Poverty_rate + Population_log + police_per_100k_lag

That is quite the formula!

OK, now again we will make a panel data frame and we will perform fit a fixed effect two-way model for time and individuals (STATE) with this data as well.

Twoways effects Within Model

Call:
plm(formula = LOTT_fmla, data = d_panel_LOTT, effect = "twoways", 
    model = "within")

Balanced Panel: n = 45, T = 31, N = 1395

Residuals:
      Min.    1st Qu.     Median    3rd Qu.       Max. 
-0.5448906 -0.0780395  0.0026738  0.0788052  0.5847263 

Coefficients:
                                  Estimate  Std. Error  t-value  Pr(>|t|)    
RTC_LAWTRUE                    -0.04687169  0.01641851  -2.8548 0.0043758 ** 
White_Female_10_to_19_years     0.62441376  0.15103427   4.1343 3.793e-05 ***
White_Female_20_to_29_years    -0.05942541  0.06332108  -0.9385 0.3481763    
White_Female_30_to_39_years     0.16028113  0.08045953   1.9921 0.0465755 *  
White_Female_40_to_49_years     0.10087510  0.08170707   1.2346 0.2172082    
White_Female_50_to_64_years    -0.37624966  0.06303172  -5.9692 3.083e-09 ***
White_Female_65_years_and_over  0.20636690  0.04742430   4.3515 1.460e-05 ***
White_Male_10_to_19_years      -0.59141591  0.14436974  -4.0965 4.457e-05 ***
White_Male_20_to_29_years       0.08717546  0.05862342   1.4870 0.1372503    
White_Male_30_to_39_years      -0.12514225  0.08588569  -1.4571 0.1453400    
White_Male_40_to_49_years      -0.21812366  0.07293615  -2.9906 0.0028375 ** 
White_Male_50_to_64_years       0.37845575  0.07314122   5.1743 2.653e-07 ***
White_Male_65_years_and_over   -0.20915907  0.06659815  -3.1406 0.0017246 ** 
Black_Female_10_to_19_years    -1.03146594  0.43610403  -2.3652 0.0181697 *  
Black_Female_20_to_29_years    -0.02721685  0.17462559  -0.1559 0.8761693    
Black_Female_30_to_39_years    -0.03246043  0.20498789  -0.1584 0.8742037    
Black_Female_40_to_49_years     0.43820099  0.23524130   1.8628 0.0627234 .  
Black_Female_50_to_64_years     0.04906111  0.21393128   0.2293 0.8186482    
Black_Female_65_years_and_over  0.07226074  0.24373031   0.2965 0.7669130    
Black_Male_10_to_19_years       1.22536162  0.44559642   2.7499 0.0060447 ** 
Black_Male_20_to_29_years      -0.06587312  0.18392655  -0.3581 0.7202909    
Black_Male_30_to_39_years       0.24720746  0.23673862   1.0442 0.2965804    
Black_Male_40_to_49_years      -0.66869983  0.27173041  -2.4609 0.0139904 *  
Black_Male_50_to_64_years      -0.16737616  0.23977741  -0.6980 0.4852740    
Black_Male_65_years_and_over   -0.58743446  0.34691532  -1.6933 0.0906404 .  
Other_Female_10_to_19_years     0.70957924  0.49539878   1.4323 0.1522910    
Other_Female_20_to_29_years    -1.16489945  0.26997487  -4.3148 1.720e-05 ***
Other_Female_30_to_39_years    -3.40258912  0.35368437  -9.6204 < 2.2e-16 ***
Other_Female_40_to_49_years     1.34563633  0.42503994   3.1659 0.0015825 ** 
Other_Female_50_to_64_years     2.93990932  0.33830653   8.6901 < 2.2e-16 ***
Other_Female_65_years_and_over  2.36026239  0.20422580  11.5571 < 2.2e-16 ***
Other_Male_10_to_19_years       0.07481449  0.47835310   0.1564 0.8757423    
Other_Male_20_to_29_years       1.62895925  0.25740603   6.3284 3.420e-10 ***
Other_Male_30_to_39_years       3.17421278  0.41184489   7.7073 2.566e-14 ***
Other_Male_40_to_49_years      -1.58494177  0.44840281  -3.5346 0.0004229 ***
Other_Male_50_to_64_years      -3.91523867  0.37399898 -10.4686 < 2.2e-16 ***
Other_Male_65_years_and_over   -4.16596244  0.36860536 -11.3020 < 2.2e-16 ***
Unemployment_rate              -0.00545734  0.00436374  -1.2506 0.2113054    
Poverty_rate                   -0.00572362  0.00253162  -2.2609 0.0239357 *  
Population_log                 -0.21716335  0.08452664  -2.5692 0.0103068 *  
police_per_100k_lag             0.00069547  0.00013331   5.2171 2.118e-07 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Total Sum of Squares:    43.211
Residual Sum of Squares: 23.647
R-Squared:      0.45275
Adj. R-Squared: 0.40355
F-statistic: 25.8088 on 41 and 1279 DF, p-value: < 2.22e-16

RTC coefficient comparison

Now let’s make a plot to compare the coefficient estimate for the Right-to-carry law adoption variable in each model.

First we will combine model fit information for this coefficient for each model.

# A tibble: 2 x 8
  term        estimate std.error statistic p.value conf.low conf.high Analysis  
  <chr>          <dbl>     <dbl>     <dbl>   <dbl>    <dbl>     <dbl> <chr>     
1 RTC_LAWTRUE   0.0180    0.0166      1.08 0.280    -0.0146    0.0506 Analysis 1
2 RTC_LAWTRUE  -0.0469    0.0164     -2.85 0.00438  -0.0791   -0.0147 Analysis 2

We can see that for the first analysis (similar to the Donohue et al. {target="_blank“} study) the coefficient estimate for the presence of a permissive Right-to-carry law is positive, while for the second analysis (similar to the Mustard and Lott study) the coefficient estimate is negative. Thus in the first analysis we could conclude that the effect of adopting permissive right-to-carry laws may be associated with increases in violent crime (although this was not a significant result (in contrast with the real Donohue et al. {target=”_blank"} study )); while in the other analysis we could conclude that the laws may be associated with decreases in violent crime.

Let’s make a plot of this finding. We will show error bars for the coefficient estimates for both analyses using the geom_errorbar() function of the ggplot2 package. This requires specifying the minimum and maximum for our error bar, which in our case we would like to be the low and high values of our confidence intervals for the coefficient estimates. We will also add a horizontal line at y = 0 using the geom_hline() function of the ggplot2 package.

Finally we will add arrows to emphasize the difference in the direction of the findings using the geom_segment() function of the ggplot2 package. Using the arrow() function, we can specify details about the arrow we would like to add.

We can see that most of the possible range of values for the estimate in analysis 1 are positive, while they are all negative for analysis 2.

Multicollinearity analysis


How did the above happen?

The analysis data frames are very similar yet rendered very different results.

Recall that the only difference is the number of demographic variables. The number of rows or observations is the same. We can use the all_equal() function of the dplyr package to compare the number of columns of our Donohue-like data and our Mustard and Lott-like data.

- different number of columns: 20 vs 50

Using the base dim() function we can also look at the number of rows for each and see that the number of observations is the same for both datasets.

[1] 1395
[1] 1395

The only difference between the two data frames rests in how the demographic variables were parameterized.

[1] "Black_Male_15_to_19_years" "Black_Male_20_to_39_years"
[3] "Other_Male_15_to_19_years" "Other_Male_20_to_39_years"
[5] "White_Male_15_to_19_years" "White_Male_20_to_39_years"
 [1] "Black_Female_10_to_19_years"    "Black_Female_20_to_29_years"   
 [3] "Black_Female_30_to_39_years"    "Black_Female_40_to_49_years"   
 [5] "Black_Female_50_to_64_years"    "Black_Female_65_years_and_over"
 [7] "Black_Male_10_to_19_years"      "Black_Male_20_to_29_years"     
 [9] "Black_Male_30_to_39_years"      "Black_Male_40_to_49_years"     
[11] "Black_Male_50_to_64_years"      "Black_Male_65_years_and_over"  
[13] "Other_Female_10_to_19_years"    "Other_Female_20_to_29_years"   
[15] "Other_Female_30_to_39_years"    "Other_Female_40_to_49_years"   
[17] "Other_Female_50_to_64_years"    "Other_Female_65_years_and_over"
[19] "Other_Male_10_to_19_years"      "Other_Male_20_to_29_years"     
[21] "Other_Male_30_to_39_years"      "Other_Male_40_to_49_years"     
[23] "Other_Male_50_to_64_years"      "Other_Male_65_years_and_over"  
[25] "White_Female_10_to_19_years"    "White_Female_20_to_29_years"   
[27] "White_Female_30_to_39_years"    "White_Female_40_to_49_years"   
[29] "White_Female_50_to_64_years"    "White_Female_65_years_and_over"
[31] "White_Male_10_to_19_years"      "White_Male_20_to_29_years"     
[33] "White_Male_30_to_39_years"      "White_Male_40_to_49_years"     
[35] "White_Male_50_to_64_years"      "White_Male_65_years_and_over"  

Clearly, this had an effect on the results of the analysis.

Let’s explore how this occurred.

When seemingly independent variables are highly related to one another, the relationships estimated in an analysis may be distorted.

In regression analysis, this distortion is often a by-product of a violation of the independence assumption. This distortion, if large enough, can impact statistical inference.

The phenomena called multicollinearity occurs when independent variables are highly related to one another

There are several ways we can diagnose multicollinearity.

Correlation

One way we can evaluate the relationships between variables is by examining the correlation between variable pairs.

It is important to note that multicollinearity and correlation are not one and the same. Correlation can be thought of as the strength of a linear relationship between variables. On the other hand, collinearity can be thought of as two independent variables having a linear relationship or association. Multicollinearity can be thought of as collinearity among multiple (3+) regressors (independent variables) in a regression analysis, which can occur when regressors are highly correlated.

According to Wikipedia:

multicollinearity (also collinearity) is a phenomenon in which one predictor variable in a multiple regression model can be linearly predicted from the others with a substantial degree of accuracy.

Thus collinearity describes linear prediction or association. Often those variables will be highly correlated.

The issue with this in linear regression, is that linear regression aims to determine how a one unit change in a regressor influences a one unit change in the dependent variable. In fact, this is what the coefficient estimates aim to tell us for each regressor.

However, if our regressors are also linearly related, than it becomes difficult to determine the effect of each regressor on the dependent variable and multicollinearity can cause instability in the estimation of coefficient estimates, making them unreliable. Coefficients may be inflated, deflated, or their signs may change.

avocado… what if the regressors have a nonlinear relationship??

avocado: I really liked these explanations - not sure if we want to include these as resources: https://blog.clairvoyantsoft.com/correlation-and-collinearity-how-they-can-make-or-break-a-model-9135fbe6936a

https://medium.com/swlh/multicollinearity-and-variance-inflation-factor-bc74af36b1c9

Scatter plots

One of the ways to diagnose multicollinearity in a regression model is to first see if there are regressors that are highly correlated. If so, this suggests that we should investigate further to see if these variables are in fact linearly predicting one another.

One way to look at correlation across pairs of variables is to use the ggpairs() function of the GGally package.

 [1] "YEAR"                      "STATE"                    
 [3] "Black_Male_15_to_19_years" "Black_Male_20_to_39_years"
 [5] "Other_Male_15_to_19_years" "Other_Male_20_to_39_years"
 [7] "White_Male_15_to_19_years" "White_Male_20_to_39_years"
 [9] "Unemployment_rate"         "Poverty_rate"             
[11] "Viol_crime_count"          "Population"               
[13] "police_per_100k_lag"       "RTC_LAW_YEAR"             
[15] "RTC_LAW"                   "TIME_0"                   
[17] "TIME_INF"                  "Viol_crime_rate_1k"       
[19] "Viol_crime_rate_1k_log"    "Population_log"           

We can see that for the non-demographic variables, there is very little correlation between the pairs of variables. Only the unemployment rate and the poverty rate show relatively strong correlation, as one might expect.

Heatmaps

Another way to look at correlation if we have many variables is to use heatmaps.

Let’s to this now for the demographic variables for each analysis.

The ggcorrplot() function of the ggpcorplot package is one way to create such a heatmap.

This requires first calculating the correlation values using the cor() function of the stats package.

We will add a legend title to include \(\rho\) by using the base expression() function, which will convert the written for of "rho" to the Greek symbol.

We can see that many of the demographic variables are highly correlated with one another.

The presence of correlation between variables suggests that we might have multicollinearity. However it does not necessarily mean that we do. So how can we assess this?

Coefficient estimate instability

One way to look at the possible influence of multicollinearity is to look at the stability of the coefficient estimates.

We will focus on the RTC_LAW variable coefficient estimate, as this is of particular interest in our case.

To do so we will perform a process called resampling. This involves performing multiple iterations of our analysis, but with only a subset or sub-sample of our original data. In our case we will remove one observation and see if that changes our coefficient estimate results.

To do this we will use some functions in the rsample package which is very useful for splitting data in various ways.

We will use the loo_cv() function which stands for leave one out [cross validation](https://en.wikipedia.org/wiki/Cross-validation_(statistics){target="_blank"}. This will allow us to split our data into every possible subset where a unique observation is left out of the data.

This function will however only prepare the data to be split.

To actually get the remaining data after the removal of the observation that is left out when need to use a function called training(). This is because these functions are often used for in machine learning applications where the data is split between a larger training set and a smaller testing set. Thus we want the larger \(n-1\) subset, as opposed to the single value that is removed, (which we could get with the testing() function)

Click here to see an example of how this works.

First we will make a toy dataset that is very simple called test using the tibble() function of the tidyr package:

# A tibble: 3 x 1
      x
  <dbl>
1     1
2     2
3     3

Now we will use the loo_cv() to create leave one out splits:

# Leave-one-out cross-validation 
# A tibble: 3 x 2
  splits        id       
  <list>        <chr>    
1 <split [2/1]> Resample1
2 <split [2/1]> Resample2
3 <split [2/1]> Resample3

We can take a look at one individual split using the pull() function:

[[1]]
<Analysis/Assess/Total>
<2/1/3>

[[2]]
<Analysis/Assess/Total>
<2/1/3>

[[3]]
<Analysis/Assess/Total>
<2/1/3>

Here you can see that 2 values are intended for the training set (also called Analysis set), 1 value is intended for the testing set (also called Assessment set), and 3 values were present initially.

Now we will use the training() function to get the data without the observation that is set aside. Here is the data for the first subset:

# A tibble: 2 x 1
      x
  <dbl>
1     1
2     2

Now we will use the map() function of purrr to get all possible training subset of the data.

[[1]]
# A tibble: 2 x 1
      x
  <dbl>
1     1
2     2

[[2]]
# A tibble: 2 x 1
      x
  <dbl>
1     1
2     3

[[3]]
# A tibble: 2 x 1
      x
  <dbl>
1     2
2     3

We can see that there are 3 possible subsets that leave one value out. All 3 possible subsets are created using this method. This method will always create the same number of subsets as there are unique values or rows in the data.

Now we will use this method with the data from our Donohue-like analysis, since this data has dim(d_panel_DONOHUE)[1] rows, dim(d_panel_DONOHUE)[1] subsets will be created that leave out one row.

First we will create the splits using the loo_cv() function:

# Leave-one-out cross-validation 
# A tibble: 1,395 x 2
   splits           id        
   <list>           <chr>     
 1 <split [1.4K/1]> Resample1 
 2 <split [1.4K/1]> Resample2 
 3 <split [1.4K/1]> Resample3 
 4 <split [1.4K/1]> Resample4 
 5 <split [1.4K/1]> Resample5 
 6 <split [1.4K/1]> Resample6 
 7 <split [1.4K/1]> Resample7 
 8 <split [1.4K/1]> Resample8 
 9 <split [1.4K/1]> Resample9 
10 <split [1.4K/1]> Resample10
# … with 1,385 more rows

Now we will use the training() function to select the remaining data without the value that was removed for each split:

Rows: 1,394
Columns: 20
$ YEAR                      <fct> 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1…
$ STATE                     <fct> Alaska, Alaska, Alaska, Alaska, Alaska, Ala…
$ Black_Male_15_to_19_years <pseries> 0.1670456, 0.1732299, 0.1737069, 0.1709…
$ Black_Male_20_to_39_years <pseries> 0.9933775, 1.0028219, 1.0204445, 1.0312…
$ Other_Male_15_to_19_years <pseries> 1.1297816, 1.1244412, 1.0698208, 0.9882…
$ Other_Male_20_to_39_years <pseries> 2.963329, 2.974775, 3.015071, 3.008048,…
$ White_Male_15_to_19_years <pseries> 3.627805, 3.558261, 3.391844, 3.222002,…
$ White_Male_20_to_39_years <pseries> 18.28852, 18.12821, 18.10666, 17.90600,…
$ Unemployment_rate         <pseries> 9.6, 9.4, 9.9, 9.9, 9.8, 9.7, 10.9, 10.…
$ Poverty_rate              <pseries> 9.6, 9.0, 10.6, 12.6, 9.6, 8.7, 11.4, 1…
$ Viol_crime_count          <pseries> 1919, 2537, 2732, 2940, 3108, 3031, 304…
$ Population                <pseries> 404680, 418519, 449608, 488423, 513697,…
$ police_per_100k_lag       <pseries> 194.7218, 200.2299, 191.0553, 364.2335,…
$ RTC_LAW_YEAR              <pseries> 1995, 1995, 1995, 1995, 1995, 1995, 199…
$ RTC_LAW                   <pseries> FALSE, FALSE, FALSE, FALSE, FALSE, FALS…
$ TIME_0                    <pseries> 1980, 1980, 1980, 1980, 1980, 1980, 198…
$ TIME_INF                  <pseries> 2010, 2010, 2010, 2010, 2010, 2010, 201…
$ Viol_crime_rate_1k        <pseries> 4.742018, 6.061851, 6.076404, 6.019373,…
$ Viol_crime_rate_1k_log    <pseries> 1.556463, 1.802015, 1.804413, 1.794983,…
$ Population_log            <pseries> 12.91085, 12.94448, 13.01613, 13.09894,…
[1] 1395

As expected the first subset has 1,394 rows and there are 1395 subsets.

Let’s see what observation was left out in the first subset:

           YEAR STATE Black_Male_15_to_19_years Black_Male_20_to_39_years
Texas-1988 1988 Texas                 0.5599219                  2.091018
           Other_Male_15_to_19_years Other_Male_20_to_39_years
Texas-1988                0.09824717                 0.4413413
           White_Male_15_to_19_years White_Male_20_to_39_years
Texas-1988                  3.447339                  14.79001
           Unemployment_rate Poverty_rate Viol_crime_count Population
Texas-1988               7.3           18           109499   16667146
           police_per_100k_lag RTC_LAW_YEAR RTC_LAW TIME_0 TIME_INF
Texas-1988            298.2274         1996   FALSE   1980     2010
           Viol_crime_rate_1k Viol_crime_rate_1k_log Population_log
Texas-1988           6.569751               1.882476       16.62895
           YEAR STATE Black_Male_15_to_19_years Black_Male_20_to_39_years
Texas-1988 1988 Texas                 0.5599219                  2.091018
           Other_Male_15_to_19_years Other_Male_20_to_39_years
Texas-1988                0.09824717                 0.4413413
           White_Male_15_to_19_years White_Male_20_to_39_years
Texas-1988                  3.447339                  14.79001
           Unemployment_rate Poverty_rate Viol_crime_count Population
Texas-1988               7.3           18           109499   16667146
           police_per_100k_lag RTC_LAW_YEAR RTC_LAW TIME_0 TIME_INF
Texas-1988            298.2274         1996   FALSE   1980     2010
           Viol_crime_rate_1k Viol_crime_rate_1k_log Population_log
Texas-1988           6.569751               1.882476       16.62895

It looks like the Texas data from 1988 was removed from the first split.

OK, so now let’s fit our panel regression on the first subset of data like we did previously. Note that this causes our data to be an unbalanced panel. This does not require any adjustment to the code to model the data, but you will notice that the output will now say “unbalanced”.

Twoways effects Within Model

Call:
plm(formula = Viol_crime_rate_1k_log ~ RTC_LAW + White_Male_15_to_19_years + 
    White_Male_20_to_39_years + Black_Male_15_to_19_years + Black_Male_20_to_39_years + 
    Other_Male_15_to_19_years + Other_Male_20_to_39_years + Unemployment_rate + 
    Poverty_rate + Population_log + police_per_100k_lag, data = DONOHUE_subsets[[1]], 
    effect = "twoways", model = "within", index = c("STATE", 
        "YEAR"))

Unbalanced Panel: n = 45, T = 30-31, N = 1394

Residuals:
      Min.    1st Qu.     Median    3rd Qu.       Max. 
-0.5795659 -0.0893732 -0.0014097  0.0865870  1.1118927 

Coefficients:
                             Estimate  Std. Error t-value  Pr(>|t|)    
RTC_LAWTRUE                0.01812436  0.01664364  1.0890 0.2763694    
White_Male_15_to_19_years -0.00103284  0.02724763 -0.0379 0.9697687    
White_Male_20_to_39_years  0.03462260  0.00973037  3.5582 0.0003868 ***
Black_Male_15_to_19_years -0.05699742  0.05747236 -0.9917 0.3215097    
Black_Male_20_to_39_years  0.12591876  0.01931901  6.5179 1.016e-10 ***
Other_Male_15_to_19_years  0.69114956  0.11325143  6.1028 1.371e-09 ***
Other_Male_20_to_39_years -0.30242747  0.03812860 -7.9318 4.603e-15 ***
Unemployment_rate         -0.01698131  0.00490345 -3.4631 0.0005512 ***
Poverty_rate              -0.00782727  0.00295795 -2.6462 0.0082384 ** 
Population_log            -0.17899715  0.06044257 -2.9614 0.0031173 ** 
police_per_100k_lag        0.00060326  0.00013692  4.4058 1.140e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Total Sum of Squares:    43.198
Residual Sum of Squares: 36.701
R-Squared:      0.15039
Adj. R-Squared: 0.095183
F-statistic: 21.0489 on 11 and 1308 DF, p-value: < 2.22e-16

Indeed, we can see that now we have an unbalanced panel with N = 1394 observations instead of 1395, as expected.

Now that we have our subsets, we want to write a function to fit a panel regression using plm()on each subsets. See this case study for more information on writing functions.

Now we can apply this function to each of our subsets simultaneously using the map() function of the purrr package.

Great! Now we want to do the same thing for the Mustard and Lott data.

We need to create a different function to fit the data to account for the larger number of demographic variables. We will use the formula that we made previously.

Now we will combine the output so that we can make a plot to visualize the results that we obtained. First let’s name each subset that we created.

Now we can combine the tibbles within the list of tibbles for the subsets_models_DONOHUE and subsets_models_LOTT data.

To do this we will use the bind_rows() function of the dplyr package with the .id = "ID" argument, which will create a new variable called ID that will list the name of the tibble the data came from.

Then we will combine the data from both the Donohue and Lott simulations.

# A tibble: 6 x 7
  ID        term                 estimate std.error statistic  p.value Analysis 
  <chr>     <chr>                   <dbl>     <dbl>     <dbl>    <dbl> <chr>    
1 DONOHUE_1 RTC_LAWTRUE           0.0181    0.0166     1.09   2.76e- 1 Analysis…
2 DONOHUE_1 White_Male_15_to_19… -0.00103   0.0272    -0.0379 9.70e- 1 Analysis…
3 DONOHUE_1 White_Male_20_to_39…  0.0346    0.00973    3.56   3.87e- 4 Analysis…
4 DONOHUE_1 Black_Male_15_to_19… -0.0570    0.0575    -0.992  3.22e- 1 Analysis…
5 DONOHUE_1 Black_Male_20_to_39…  0.126     0.0193     6.52   1.02e-10 Analysis…
6 DONOHUE_1 Other_Male_15_to_19…  0.691     0.113      6.10   1.37e- 9 Analysis…
# A tibble: 6 x 7
  ID       term                  estimate std.error statistic  p.value Analysis 
  <chr>    <chr>                    <dbl>     <dbl>     <dbl>    <dbl> <chr>    
1 LOTT_13… Other_Male_50_to_64_… -3.91e+0  0.375       -10.4  1.66e-24 Analysis…
2 LOTT_13… Other_Male_65_years_… -4.16e+0  0.369       -11.3  3.97e-28 Analysis…
3 LOTT_13… Unemployment_rate     -5.43e-3  0.00437      -1.24 2.14e- 1 Analysis…
4 LOTT_13… Poverty_rate          -5.75e-3  0.00253      -2.27 2.33e- 2 Analysis…
5 LOTT_13… Population_log        -2.16e-1  0.0846       -2.55 1.08e- 2 Analysis…
6 LOTT_13… police_per_100k_lag    6.96e-4  0.000133      5.22 2.07e- 7 Analysis…

Now we will make a jitter plot using the geom_jitter() function of the coefficient estimates of the RTC_LAWTRUE variable for each simulation.

Since there are many variables in both analyses, we will use the facet_grid() function of the ggplot2 package to allow us to separate the data for each analysis into subplots. The argument scale = "free_x" and drop = TRUE allow us to only include the variables that were present in Analysis 1, as opposed to empty spots for the variables that were in Analysis 2 but not in Analysis 1. The space = "free" argument removes the extra space from the dropped variables.

Question Opportunity

What happens if don’t use the drop = TRUE argument or the space = "free" argument?

We can see that the range of coefficient estimates when only one observation is removed is much larger in Analysis 2 for nearly all variables, but particularly for many of the additional demographic variables.

Let’s make a plot showing the summary of the overall coefficient instability.

To do this we will calculate the standard deviation of coefficient estimates for each variable across all of the simulations. Thus we will group by the Analysis and the term variables now that our data is in long format. We will use the sd() function of the stats package to calculate the standard deviation.

Now we will make a plot of this data.

Here we can clearly see that overall the coefficient estimates are much less stable in Analysis 2. This is a clear indication that we have multicollinearity.

from Michael

sims <- 250

# DONOHUE
samps_DONOHUE <- lapply(rep(dim(DONOHUE_DF)[1]/2, sims),
       function(x)DONOHUE_DF[sample(nrow(DONOHUE_DF),
                                     size = x, replace = FALSE),])

fit_nls_on_bootstrap_DONOHUE <- function(split){
  plm(Viol_crime_rate_1k_log ~
                        RTC_LAW +
                        White_Male_15_to_19_years +
                        White_Male_20_to_39_years +
                        Black_Male_15_to_19_years +
                        Black_Male_20_to_39_years +
                        Other_Male_15_to_19_years +
                        Other_Male_20_to_39_years +
                        Unemployment_rate +
                        Poverty_rate + 
                        Population_log + 
                        police_per_100k_lag,
      data = data.frame(split),
      index = c("STATE","YEAR"),
      model = "within",
      effect = "twoways")
}
  
samps_models_DONOHUE <- lapply(samps_DONOHUE, fit_nls_on_bootstrap_DONOHUE)

samps_models_DONOHUE <- samps_models_DONOHUE %>%
  map(tidy)

names(samps_models_DONOHUE) <- paste0("DONOHUE_",1:length(samps_models_DONOHUE))

simulations_DONOHUE <- samps_models_DONOHUE %>%
  bind_rows(.id = "ID") %>%
  mutate(Analysis = "Analysis 1")

## Mustard and Lott

samps_LOTT <- lapply(rep(round(dim(LOTT_DF)[1]/2), sims),
       function(x) LOTT_DF[sample(nrow(LOTT_DF),
                                  size = x, replace = FALSE),])

fit_nls_on_bootstrap_LOTT <- function(split){
  plm(LOTT_fmla,
      data = data.frame(split),
      index = c("STATE","YEAR"),
      model = "within",
      effect = "twoways")
}
  
samps_models_LOTT <- lapply(samps_LOTT, fit_nls_on_bootstrap_LOTT)

samps_models_LOTT <- samps_models_LOTT %>%
  map(tidy)

names(samps_models_LOTT) <- paste0("LOTT_",1:length(samps_models_LOTT))

simulations_LOTT <- samps_models_LOTT %>%
  bind_rows(.id = "Analysis") %>%
  mutate(Analysis = "Analysis 2")

simulations <- bind_rows(simulations_DONOHUE,
                         simulations_LOTT)

simulation_plot <- simulations %>%
  filter(term=="RTC_LAWTRUE") %>%
  ggplot(aes(x = Analysis, y = estimate)) + 
  geom_boxplot(alpha = 0.25,
              width = 0.1) + 
  labs(title = "Coefficient instability",
       subtitle = "Estimates sensitive to observation deletions",
       x = "Term",
       y = "Coefficient",
       caption = "Results from simulations") + 
  theme_minimal() +
  theme(axis.title.x = element_blank())

simulation_plot

VIF

Another way of evaluating the presence and severity of multicollinearity is to calculate the variance inflation factor (VIF) .

According to Wikipedia:

It provides an index that measures how much the variance (the square of the estimate’s standard deviation) of an estimated regression coefficient is increased because of collinearity.

The variance inflation factor (VIF) is the quotient of the variance in a model with multiple terms by the variance of a model with one term alone.

VIF values can be calculated for each explanatory variable in a model by performing the following calculation:

  1. Run another ordinary least squares (OLS) linear regression with one of the explanatory variables of your model of interest (\(Xi\)) as the dependent variable and keep the remaining explanatory variables as explanatory variables.

So generically speaking say this is our model:

\[Y = β_0 + β_1X_1 + β_2X_2 + β_3X_3 \] We have three explanatory variables (\(X_1\), \(X_2\), and \(X_3\)).

If we want to calculate the VIF value for \(X_1\) we would need to perform another OLS model, where \(X1\) is now the dependent variable explained by the other explanatory variables.

\[X_1 = β_0 + β_2X_2 + β_3X_3 \]

The \(R^2\) coefficient of determination also called R squared value from this regression is then used to calculate the VIF as follows:

\[\frac{1}{1-R^{2}}\]

The \(R^2\) value is in this case the proportion of variance in \(X_1\) explained by the other variables (\(X_2\) and \(X_3\)).

VIF values are typically calculated for each explanatory variable when evaluating multicollinearity of a model.

Thus overall the calculation is: \[VIF_i = \frac{1}{1-R_i^{2}}\] Where \(i\) corresponds to each explanatory variable.

Recall that according to Wikipedia:

The variance inflation factor (VIF) is the quotient of the variance in a model with multiple terms by the variance of a model with one term alone.

The \(R^2\) value ranges from 0 to 1. Thus, if a variation of a variable is highly explained by the other variables, the \(R^2\) will approach 1. Thus the denominator in the VIF calculation \(1-R_i^{2}\) (which is sometimes referred to as tolerance) will be smaller and the VIF value will be larger.

Thus, higher VIF vales indicate more severe multicollinearity. Typically a threshold of a tolerance of less than 0.10 and/or a VIF of 10 and above is used as a rule of thumb to determine if the presence of multicollinearity might be problematic.

Please see this article for a thorough explanation of how to interpret VIF values and how to decide what to do if your model has high multicollinearity.

So how do we calculate VIF values in R?

We could do this manually creating many linear regressions, but that would obviously be time consuming. Luckily, the car package has a function called vif() that will calculate VIF values.

avocado: Idk if this is true or if we need to do what Michael did? https://stackoverflow.com/questions/20281055/test-for-multicollinearity-in-panel-data-r

Since VIF values are calculated using only the independent variables, we don’t need to worry about the effect of time and individuals in our calculation, thus we will use the pooled model. Otherwise, the vif() function is incompatible with the output from the plm() function.

Then we will create nicer looking output of the data using the as_tibble()function of the tibble package to create a tibble and add the variable names as another column.

                  RTC_LAW White_Male_15_to_19_years White_Male_20_to_39_years 
                 1.465544                  5.984923                  3.825518 
Black_Male_15_to_19_years Black_Male_20_to_39_years Other_Male_15_to_19_years 
                15.063716                 18.065119                 46.313201 
Other_Male_20_to_39_years         Unemployment_rate              Poverty_rate 
                47.441021                  1.497460                  1.645000 
           Population_log       police_per_100k_lag 
                 1.324506                  2.393953 
         VIF                  Variable
1   1.465544                   RTC_LAW
2   5.984923 White_Male_15_to_19_years
3   3.825518 White_Male_20_to_39_years
4  15.063716 Black_Male_15_to_19_years
5  18.065119 Black_Male_20_to_39_years
6  46.313201 Other_Male_15_to_19_years
7  47.441021 Other_Male_20_to_39_years
8   1.497460         Unemployment_rate
9   1.645000              Poverty_rate
10  1.324506            Population_log
11  2.393953       police_per_100k_lag

Now we will do the same for the Mustard and Lott data:

We can see that some of the VIF values are very high!

avocado:From Michael: he calculated the time-demeaned response variable based on this link: http://karthur.org/2019/implementing-fixed-effects-panel-models-in-r.html

Idk if we need to/should do this. The values are different.- lower in general.If so though this is how one would do it.

This vif() function is not compatible with the plm package panel data frames and linear model outputs, thus we need to create a design matrix with the plm package using the Within() function and then use the lm() function of the stats package to fit the model.

Now we will make a plot of the VIF values for both analyses:

We can see that both analyses have some variables with relatively high multicollinearity, however analysis 2 has variables with very high multicollinearity.

In many cases it would be advisable to remove one or more of these variables and reassess the VIF values. There are also other options, such as ridge regression. However, both of these options need to be done with care as they can also introduce bias into the model.

In any case the presence of multicollinearity should encourage further investigation about the design of the model, as the results may not be reliable due to the increased level of instability of the coefficients estimates.

See this this article for a detailed discussion about what to consider when your model has variables with high VIF values.

Data Visualization


Now lets make a plot that summarizes all of our findings.

We will use the cowplot package to put our plots together.

We will use the ggdraw() function of this package. This allows you to add labels and other plot aspects on top of existing plots. Thus if we want to add a title element to our overall plot that we will add to a combined plot of our existing plots we can use ggdraw() to start and then the draw_label() function to add text.

[1] "gg"     "ggplot"

As you can see we know have plot object that just has the text "Multicollinearity and its effects".

Now we will create a subtitle in the same way.

Now we will recreate our correlation plots with some slight alterations. We want to remove our labels, because they will be too small to see when we combine our plots. To do this we will use the theme_void() function of the ggplot2 package.

Note that because we are layering ggplot2 objects we can’t use the %>% pipe to start with the existing correlation plots.

OK we want to arrange our correlation plots to be in the top row of our larger plot. Now we will use the plot_grid() function to arrange the plots.

Nice! We have combined plots!

Now let’s add a title for these plots.

For our second row in our larger plot we want to have the formula for calculating VIF values on the left and the plot that we created previously showing VIF values on the right.

First we will create a plot object that just has the formula.

To do so we are going to create a plot with a large label in the middle containing the formula. Then we will use the theme_void() function again to remove the axis labels and background.

To create our plot we will first plot values from 1-10 for both the x and y axis, allowing us to center the formula at x and y values of 5.

To type the formal we need to use LaTeX mathematical notation.

The start and end of inline mathematical formulas are specified using dollar signs ($).
Subscripts are written by using an underscore (_) and brackets ({}) indicate the start and end of the subscript.

Fractions are indicated using \frac{nominator}{denominator}.

Superscripts are created using the carrot symbol (^) and brackets ({}) indicate the start and end of the superscript.

Greek letters are created by using \beta

In the case of the fraction and Greek letters an additional \ is needed in the Tex() function.

We will use the TeX() function of the latex2exp package to convert our LaTeX string to a plotmath expression (a mathematical notation in R to be used in plots.)

Now we will combine this with the VIF plot.

Now for the third row we want to include the comparing_analyses_plot and the simulation_plot.

Now that we have all of our rows we can combine everything together.

from Michael

plot_A1 <- corr_mat_DONOHUE

plot_A2 <- corr_mat_LOTT

row_A <- plot_grid(plot_A1,
                   plot_A2,
                   nrow = 1)

title_A <- ggdraw() + 
  draw_label(
    "Correlation between variables can induce multicollinearity",
    fontface = 'bold',
    size=14,
    x = 0,
    hjust = -.01
  ) +
  theme(
    plot.margin = margin(0, 0, 0, 0)
  )

legend_A <- get_legend(corr_mat_LOTT)

plot_A <- plot_grid(title_A,
                    row_A,
                    ncol = 1,
                    rel_heights = c(0.1,1))

empty_df <- cbind(c(1:10),c(1:10)) %>%
  as.data.frame()

colnames(empty_df) <- c("X", "Y")

plot_B1 <- ggplot(empty_df, aes(x = X, y = Y)) +
  annotate("text",
           x=5,
           y=5,
           label = TeX("$VIF_{i} = \\frac{1}{1-R_{i}^{2}}$"),
           size = 8) +
  theme_void()

plot_B2 <- vif_plot +
  theme(axis.title.x = element_text(size=8))

row_B <- plot_grid(plot_B1,
                       plot_B2,
                       nrow = 1)

title_B <- ggdraw() + 
  draw_label(
    "Variance inflation factors can be used to identify multicollinearity when present",
    fontface = 'bold',
    size=14,
    x = 0,
    hjust = 0
  ) +
  theme(
    plot.margin = margin(0, 0, 0, 0)
  )

plot_B <- plot_grid(title_B,
                    row_B,
                    ncol = 1,
                    rel_heights = c(0.1,1))

plot_C1 <- comparing_analyses_plot + 
  theme(axis.text.x = element_text(size = 8),
        axis.title.x = element_blank()) +
  labs(title = "Introduces bias to estimates",
       subtitle = "Bias introduced can change direction of estimate")

plot_C2 <- simulation_plot +
  labs(title = "Reduces precision in estimates")

row_C <- plot_grid(plot_C1,
                       plot_C2,
                       nrow = 1)

title_C <- ggdraw() + 
  draw_label(
    "Multicollinearity can have a negative effect on statistical inference",
    fontface = 'bold',
    size=14,
    x = 0,
    hjust = 0
  ) +
  theme(
    plot.margin = margin(0, 0, 0, 0)
  )

plot_C <- plot_grid(title_C,
                    row_C,
                    ncol = 1,
                    rel_heights = c(0.1,1))

plots <- plot_grid(plot_A,
                   plot_B,
                   plot_C,
          ncol = 1,
          rel_heights = c(1,1,1))

mainplot <- plot_grid(title_plots,
                       forward,
                       plots,
                       #legend_uw,
                       ncol = 1,
                       rel_heights = c(0.05,
                                       0.05,
                                       1))

mainplot

Summary


This case study has introduced the concept of multicollinearity by exploring data related to violent crimes and right-to-carry gun laws. We also introduced the topic of panel data as a special type of longitudinal data that includes data of 2 or more individuals or groups over 2 or more time points. We learned that we can use the plm package to perform panel linear regression analysis. We learned that the fixed effect model in panel analysis actually makes the least assumptions, and is therefore often the most appropriate test.

By evaluating two analyses that were identical except for the inclusion of extra demographic variables, analysis 1 included 6, while analysis 2 included 36, we discovered that redundant and collinear variables can change the directionality and magnitude of our findings.

We learned that by looking at the correlation between pairs of explanatory variables we can get a sense about whether multicollinearity may exist in our data.

We learned that we can evaluate the stability of our coefficient estimates across sub-samples or calculate variance inflation factor (VIF) values to get a sense of the presence and severity of multicollinearity.

We learned that often a rule of thumb of >10 is used as a threshold for raising concern about the severity of multicollinearity. However, we also learned that (as often is the case with thresholds) more care may be required.

Overall we learned that multicollinearity can bias our regression findings and it is good practice to check for multicollinearity when performing regression analysis. It is something to keep in mind when we encounter coefficient estimates that are unexpected.

Importantly this case study showcases how methodological details, like how we decide to parse our demographic variables can have great consequences on the results of our analyses.

Homework


Ask students to remove one or more of the demographic variables with high VIF values from the Mustard and Lott-like panel data and perform the panel linear regression analysis again, as well as calculate the VIF values.

Ask the students to discuss how this possibly changed the results.

Additional Information


Session Info

R version 4.0.1 (2020-06-06)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Mojave 10.14.5

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] DT_0.14           rsample_0.0.7     ggcorrplot_0.1.3  viridis_0.5.1    
 [5] viridisLite_0.3.0 latex2exp_0.4.0   scales_1.1.1      ggrepel_0.8.2    
 [9] GGally_2.0.0      ggplot2_3.3.1     cowplot_1.0.0     broom_0.5.6      
[13] plm_2.2-3         car_3.0-8         carData_3.0-4     tibble_3.0.1     
[17] forcats_0.5.0     purrr_0.3.4       stringr_1.4.0     tidyr_1.1.0      
[21] magrittr_1.5      dplyr_1.0.0       pdftools_2.3.1    readr_1.3.1      
[25] readxl_1.3.1      knitr_1.28        here_0.1         

loaded via a namespace (and not attached):
 [1] nlme_3.1-148       naniar_0.5.1       RColorBrewer_1.1-2 rprojroot_1.3-2   
 [5] repr_1.1.0         tools_4.0.1        backports_1.1.7    utf8_1.1.4        
 [9] R6_2.4.1           mgcv_1.8-31        colorspace_1.4-1   withr_2.2.0       
[13] tidyselect_1.1.0   gridExtra_2.3      curl_4.3           compiler_4.0.1    
[17] cli_2.0.2          sandwich_2.5-1     labeling_0.3       lmtest_0.9-37     
[21] askpass_1.1        digest_0.6.25      foreign_0.8-80     rmarkdown_2.2     
[25] rio_0.5.16         base64enc_0.1-3    pkgconfig_2.0.3    htmltools_0.4.0   
[29] bibtex_0.4.2.2     highr_0.8          htmlwidgets_1.5.1  rlang_0.4.6       
[33] generics_0.0.2     farver_2.0.3       zoo_1.8-8          jsonlite_1.6.1    
[37] crosstalk_1.1.0.1  zip_2.0.4          Formula_1.2-3      Matrix_1.2-18     
[41] fansi_0.4.1        Rcpp_1.0.4.6       munsell_0.5.0      abind_1.4-5       
[45] lifecycle_0.2.0    furrr_0.1.0        visdat_0.5.3       stringi_1.4.6     
[49] yaml_2.2.1         gbRd_0.4-11        MASS_7.3-51.6      plyr_1.8.6        
[53] grid_4.0.1         parallel_4.0.1     listenv_0.8.0      bdsmatrix_1.3-4   
[57] crayon_1.3.4       lattice_0.20-41    splines_4.0.1      haven_2.3.1       
[61] hms_0.5.3          pillar_1.4.4       reshape2_1.4.4     codetools_0.2-16  
[65] glue_1.4.1         evaluate_0.14      qpdf_1.1           data.table_1.12.8 
[69] vctrs_0.3.1        Rdpack_0.11-1      miscTools_0.6-26   cellranger_1.1.0  
[73] gtable_0.3.0       assertthat_0.2.1   reshape_0.8.8      future_1.17.0     
[77] xfun_0.14          openxlsx_4.1.5     skimr_2.1.1        maxLik_1.3-8      
[81] globals_0.12.5     ellipsis_0.3.1    

Acknowledgements

We would like to acknowledge Daniel Webster for assisting in framing the major direction of the case study.

We would also like to acknowledge the Bloomberg American Health Initiative for funding this work.

LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXM6IEluZmx1ZW5jZSBvZiBNdWx0aWNvbGxpbmVhcml0eSBvbiBNZWFzdXJlZCBJbXBhY3Qgb2YgUmlnaHQtdG8tQ2FycnkgR3VuIExhd3MiCmNzczogc3R5bGUuY3NzCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgc2VsZl9jb250YWluZWQ6IHllcwogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKPHN0eWxlPgojVE9DIHsKICBiYWNrZ3JvdW5kOiB1cmwoImh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9pbWcvbG9nby5qcGciKTsKICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47CiAgcGFkZGluZy10b3A6IDI0MHB4ICFpbXBvcnRhbnQ7CiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsKfQo8L3N0eWxlPgoKCi0tLQoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY2FjaGUgPSBGQUxTRSwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTcsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgb3V0LndpZHRoID0gJzkwJScpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShrbml0cikKCmBgYAoKCgoKIyMjIyB7Lm91dGxpbmUgfQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIm1haW5wbG90LnBuZyIpKQpgYGAKCiMjIyMKCiMjIHsuZGlzY2xhaW1lcl9ibG9ja30KCioqRGlzY2xhaW1lcioqOiBUaGUgcHVycG9zZSBvZiB0aGUgW09wZW4gQ2FzZSBTdHVkaWVzXShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8pe3RhcmdldD0iX2JsYW5rIn0gcHJvamVjdCBpcyAqKnRvIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgdmFyaW91cyBkYXRhIHNjaWVuY2UgbWV0aG9kcywgdG9vbHMsIGFuZCBzb2Z0d2FyZSBpbiB0aGUgY29udGV4dCBvZiBtZXNzeSwgcmVhbC13b3JsZCBkYXRhKiouIEEgZ2l2ZW4gY2FzZSBzdHVkeSBkb2VzIG5vdCBjb3ZlciBhbGwgYXNwZWN0cyBvZiB0aGUgcmVzZWFyY2ggcHJvY2VzcywgaXMgbm90IGNsYWltaW5nIHRvIGJlIHRoZSBtb3N0IGFwcHJvcHJpYXRlIHdheSB0byBhbmFseXplIGEgZ2l2ZW4gZGF0YSBzZXQsIGFuZCBzaG91bGQgbm90IGJlIHVzZWQgaW4gdGhlIGNvbnRleHQgb2YgbWFraW5nIHBvbGljeSBkZWNpc2lvbnMgd2l0aG91dCBleHRlcm5hbCBjb25zdWx0YXRpb24gZnJvbSBzY2llbnRpZmljIGV4cGVydHMuIAoKIyMgey5saWNlbnNlX2Jsb2NrfQoKVGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBDcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uLU5vbkNvbW1lcmNpYWwgMy4wIFsoQ0MgQlktTkMgMy4wKV0oaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLzMuMC91cy8pe3RhcmdldD0iX2JsYW5rIn0gIFVuaXRlZCBTdGF0ZXMgTGljZW5zZS4KCiMjIHsucmVmZXJlbmNlX2Jsb2NrfQoKVG8gY2l0ZSB0aGlzIGNhc2Ugc3R1ZHkgcGxlYXNlIHVzZToKCldyaWdodCwgQ2FycmllLCBhbmQgT250aXZlcm9zLCBNaWNoYWVsIGFuZCBKYWdlciwgTGVhaCBhbmQgVGF1YiwgTWFyZ2FyZXQgYW5kIEhpY2tzLCBTdGVwaGFuaWUuICgyMDIwKS4gaHR0cHM6Ly9naXRodWIuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtUlRDLWFuYWx5c2lzLiBJbmZsdWVuY2Ugb2YgTXVsdGljb2xsaW5lYXJpdHkgb24gTWVhc3VyZWQgSW1wYWN0IG9mIFJpZ2h0LXRvLUNhcnJ5IEd1biBMYXdzIChWZXJzaW9uIHYxLjAuMCkuCgoKIyAqKk1vdGl2YXRpb24qKgoqKiogCgpUaGlzIGNhc2Ugc3R1ZHkgd2lsbCBpbnRyb2R1Y2UgdGhlIHRvcGljIG9mIFttdWx0aWNvbGxpbmVhcml0eV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTXVsdGljb2xsaW5lYXJpdHkpe3RhcmdldD0iX2JsYW5rIn0sIHdoaWNoIG9jY3VycyBpbiByZWdyZXNzaW9uIHdoZW4gb25lIG9yIG1vcmUgaW5kZXBlbmRlbnQgdmFyaWFibGUgY2FuIGJlIHByZWRpY3RlZCBieSBvdGhlciBpbmRlcGVuZGVudCB2YXJhaWJsZXMuIAoKV2Ugd2lsbCBkbyBzbyBieSBzaG93Y2FzaW5nIGEgcmVhbCB3b3JsZCBleGFtcGxlIHdoZXJlIG11bHRpY29sbGluZWFyaXR5IGluIHBhcnQgcmVzdWx0ZWQgaW4gaGlzdG9yaWNhbGx5IGNvbnRyb3ZlcnNpYWwgYW5kIGNvbmZsaWN0aW5nIGZpbmRpbmdzIGFib3V0IHRoZSBpbmZsdWVuY2Ugb2YgdGhlIGFkb3B0aW9uIG9mIHJpZ2h0LXRvLWNhcnJ5IChSVEMpIGNvbmNlYWxlZCBoYW5kZ3VuIGxhd3Mgb24gdmlvbGVudCBjcmltZSByYXRlcyBpbiB0aGUgVW5pdGVkIFN0YXRlcy4gCgpXZSB3aWxsIGZvY3VzIG9uIHR3byBhcnRpY2xlczoKCjEuIFRoZSBmaXJzdCBhbmFseXNpcyBieSBbTXVzdGFyZCBhbmQgTG90dF0oaHR0cHM6Ly9jaGljYWdvdW5ib3VuZC51Y2hpY2Fnby5lZHUvY2dpL3ZpZXdjb250ZW50LmNnaT9hcnRpY2xlPTExNTAmY29udGV4dD1sYXdfYW5kX2Vjb25vbWljcyl7dGFyZ2V0PSJfYmxhbmsifSBwdWJsaXNoZWQgaW4gMTk5NiBzdWdnZXN0cyB0aGF0IFJUQyBsYXdzIHJlZHVjZSB2aW9sZW50IGNyaW1lLiBMb3R0IGF1dGhvcmVkIGEgYm9vayBleHRlbmRpbmcgdGhlc2UgZmluZGluZ3MgaW4gMTk5OCBjYWxsZWQgWyoqKk1vcmUgR3VucywgTGVzcyBDcmltZSoqKl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTW9yZV9HdW5zLF9MZXNzX0NyaW1lKXt0YXJnZXQ9Il9ibGFuayJ9LgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC5oZWlnaHQgPSAnMTAwJScsIG91dC53aWR0aCA9ICcxMDAlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiTG90dC5wbmciKSkKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vY2hpY2Fnb3VuYm91bmQudWNoaWNhZ28uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTUwJmNvbnRleHQ9bGF3X2FuZF9lY29ub21pY3Mpe3RhcmdldD0iX2JsYW5rIn0KCjIuIFRoZSBzZWNvbmQgYW5hbHlzaXMgaXMgYSByZWNlbnQgYXJ0aWNsZSBieSBbRG9ub2h1ZSwgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSBwdWJsaXNoZWQgaW4gMjAxNyB0aGF0IHN1Z2dlc3RzIHRoYXQgUlRDIGxhd3MgaW5jcmVhc2UgdmlvbGVudCBjcmltZS4gRG9ub2h1ZSBoYXMgYWxzbyBwdWJsaXNoZWQgcHJldmlvdXMgYXJ0aWNsZXMgd2l0aCB0aXRsZXMgc3VjaCBhcyBbKioqU2hvb3RpbmcgZG93biB0aGUgIk1vcmUgR3VucywgTGVzcyBDcmltZSIgSHlwb3RoZXNpcyoqKl0oaHR0cHM6Ly93d3cuanN0b3Iub3JnL3N0YWJsZS8xMjI5NjAzP3NlcT0xKXt0YXJnZXQ9Il9ibGFuayJ9LiAKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQuaGVpZ2h0ID0gJzEwMCUnLCBvdXQud2lkdGggPSAnMTAwJScsIGZpZy5hbGlnbj0nY2VudGVyJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgIkRvbm9odWUucG5nIikpCmBgYAoKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifQoKVGhpcyBoYXMgYmVlbiBhIGNvbnRyb3ZlcnNpYWwgdG9waWMgYXMgbWFueSBvdGhlciBhcnRpY2xlcyBhbHNvIGhhZCBjb25mbGljdGluZyByZXN1bHRzLiBTZWUgW2hlcmVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01vcmVfR3VucyxfTGVzc19DcmltZSl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgYSBsaXN0IG9mIHN0dWRpZXMuCgpUaGUgW0Rvbm9odWUsIGV0IGFsLl0oaHR0cHM6Ly93d3cubmJlci5vcmcvcGFwZXJzL3cyMzUxMC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gYXJ0aWNsZSBkaXNjdXNzZXMgaG93IHRoZXJlIGFyZSBtYW55IG90aGVyIGltcG9ydGFudCBtZXRob2RvbG9naWNhbCBhc3BlY3RzIGJlc2lkZXMgW211bHRpY29sbGluZWFyaXR5XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9NdWx0aWNvbGxpbmVhcml0eSl7dGFyZ2V0PSJfYmxhbmsifSAod2hpY2ggb2NjdXJzIHdoZW4gaW5kZXBlbmRlbnQgdmFyYWlibGVzIGFyZSBoaWdobHkgcmVsYXRlZCBpbiBhIHJlZ3Jlc3Npb24gYW5hbHlzaXMpIHRoYXQgY291bGQgYWNjb3VudCBmb3IgdGhlIGhpc3RvcmljYWxseSBjb25mbGljdGluZyByZXN1bHRzIGluIHRoZXNlIHByZXZpb3VzIHBhcGVycy4KCkluIGZhY3QsIG5lYXJseSBldmVyeSBhc3BlY3Qgb2YgdGhlIGRhdGEgYW5hbHlzaXMgcHJvY2VzcyB3YXMgZGlmZmVyZW50IGJldHdlZW4gdGhlIFtEb25vaHVlLCBldCBhbC5dKGh0dHBzOi8vd3d3Lm5iZXIub3JnL3BhcGVycy93MjM1MTAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IGFuYWx5c2lzIGFuZCB0aGUgW011c3RhcmQgYW5kIExvdHRdKGh0dHBzOi8vY2hpY2Fnb3VuYm91bmQudWNoaWNhZ28uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTUwJmNvbnRleHQ9bGF3X2FuZF9lY29ub21pY3Mpe3RhcmdldD0iX2JsYW5rIn0gYW5hbHlzaXMuCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICc3NSUnLCBvdXQud2lkdGggPSAnNzUlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiRWR1Y2F0aW9uYWxfR3JhcGhpYzEuanBnIikpCmBgYAoKQVZPQ0FETzogSSBsaWtlIHRoZSBncmFwaGljISBTaG91bGQgd2UgbWVudGlvbiB0aGlzIHByb2Nlc3MgaXMgYWN0dWFsbHkgaW52ZXN0aWdhdGluZyB0aGUgcmVwbGljYWJpbGl0eSAoZS5nLiB0aGlzIHBhcGVyIGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNTYyLTAxOS0wNjI5LXopIG9mIHRoZSBzdHVkeSBhcyBzdGFydGluZyB3aXRoIHRoZSBkYXRhIGFyZSBkaWZmZXJlbnQ/IAoKSG93ZXZlciwgd2Ugd2lsbCBmb2N1cyBwYXJ0aWN1bGFybHkgb24gbXVsdGljb2xsaW5lYXJpdHkgYW5kIGhvdyBpdCBjYW4gaW5mbHVlbmNlIHRoZSByZXN1bHRzIHdlIGdldCBmcm9tIGxpbmVhciByZWdyZXNzaW9uLiAKU3BlY2lmaWNhbGx5LCB0aGlzIGFuYWx5c2lzIHdpbGwgZGVtb25zdHJhdGUgaG93IG1ldGhvZG9sb2dpY2FsIGRldGFpbHMgY2FuIGJlIGNyaXRpY2FsbHkgaW5mbHVlbnRpYWwgZm9yIG91ciBvdmVyYWxsIGNvbmNsdXNpb25zIGFuZCBjYW4gcmVzdWx0IGluIGltcG9ydGFudCBwb2xpY3kgcmVsYXRlZCBjb25zZXF1ZW5jZXMuIFRoZSBbRG9ub2h1ZSwgZXQgYWwuIGFydGljbGVdKChodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSkgd2lsbCBwcm92aWRlIGEgYmFzaXMgZm9yIHRoZSBtb3RpdmF0aW9uLiAKCiMjIyMgey5yZWZlcmVuY2VfYmxvY2t9CgpKb2huIEouIERvbm9odWUgZXQgYWwuLCBSaWdodOKAkHRv4oCQQ2FycnkgTGF3cyBhbmQgVmlvbGVudCBDcmltZTogQSBDb21wcmVoZW5zaXZlIEFzc2Vzc21lbnQgVXNpbmcgUGFuZWwgRGF0YSBhbmQgYSBTdGF0ZeKAkExldmVsIFN5bnRoZXRpYyBDb250cm9sIEFuYWx5c2lzLiAqSm91cm5hbCBvZiBFbXBpcmljYWwgTGVnYWwgU3R1ZGllcyosIDE2LDIgKDIwMTkpLgoKRGF2aWQgQi4gTXVzdGFyZCAmIEpvaG4gTG90dC4gQ3JpbWUsIERldGVycmVuY2UsIGFuZCBSaWdodC10by1DYXJyeSBDb25jZWFsZWQgSGFuZGd1bnMuICpDb2FzZS1TYW5kb3IgSW5zdGl0dXRlIGZvciBMYXcgJiBFY29ub21pY3MqIFdvcmtpbmcgUGFwZXIgTm8uIDQxLCAoMTk5NikuCgojIyMjCgoKQmVmb3JlIHdlIGxlYXZlIHRoaXMgc2VjdGlvbiwgd2UgcHJvdmlkZSBhIGhpZ2gtbGV2ZWwgb3ZlcnZpZXcgb2Ygd2hhdCB2YXJpYWJsZXMgd2VyZSAob3Igd2VyZSBub3QpIGluY2x1ZGVkIGluIHRoZSBbRG9ub2h1ZSwgQW5lamEgYW5kIFdlYmVyXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSkgKERBVykgcGFwZXIgYW5kIHRoZSBbTXVzdGFyZCBhbmQgTG90dF0oaHR0cHM6Ly9jaGljYWdvdW5ib3VuZC51Y2hpY2Fnby5lZHUvY2dpL3ZpZXdjb250ZW50LmNnaT9hcnRpY2xlPTExNTAmY29udGV4dD1sYXdfYW5kX2Vjb25vbWljcyl7dGFyZ2V0PSJfYmxhbmsifSAoTUwpIHBhcGVyOgoKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQuaGVpZ2h0ID0gJzEwMCUnLCBvdXQud2lkdGggPSAnMTAwJScsIGZpZy5hbGlnbj0nY2VudGVyJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwnRG9ub2h1ZV9UYWJsZTJfZWRpdGVkLnBuZycpKQpgYGAKCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly93d3cubmJlci5vcmcvcGFwZXJzL3cyMzUxMC5wZGYpe3RhcmdldD0iX2JsYW5rIn0KCgojIyMjIyMgKk1MIGlzIGFiYnJldmlhdGVkIGFzIExNIGluIHRoZSBzb3VyY2UgYXJ0aWNsZQoKKipOb3RlKio6IFdlIGFyZSBub3QgYXR0ZW1wdGluZyB0byByZS1jcmVhdGUgdGhlIGFuYWx5c2VzIGZyb20gdGhlIG9yaWdpbmFsIGF1dGhvcnMuIEluc3RlYWQsIHdlIGFpbSB0byB1c2UgYSBzdWJzZXQgb2YgdGhlIGxpc3RlZCBleHBsYW5hdG9yeSB2YXJpYWJsZXMgaW4gdGhpcyBjYXNlIHN0dWR5IHRvIGRlbW9uc3RyYXRlIG11bHRpY29sbGluZWFyaXR5LiBUaGVzZSB2YXJpYWJsZXMgd2lsbCBiZSBjb25zaXN0ZW50IGZvciBib3RoIGFuYWx5c2VzIHRoYXQgd2Ugd2lsbCBwZXJmb3JtLCB3aXRoIHRoZSBleGNlcHRpb24gdGhhdCBvbmUgYW5hbHlzaXMgd2lsbCBoYXZlIDYgZGVtb2dyYXBoaWMgdmFyaWFibGVzIGxpa2UgdGhlIGFuYWx5c2lzIGluIHRoZSBbRG9ub2h1ZSwgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSBhcnRpY2xlIGFuZCB0aGUgb3RoZXIgd2lsbCBoYXZlIDM2IGRlbW9ncmFwaGljIHZhcmlhYmxlcyBsaWtlIHRoZSBhbmFseXNpcyBpbiB0aGUgW011c3RhcmQgYW5kIExvdHRdKGh0dHBzOi8vY2hpY2Fnb3VuYm91bmQudWNoaWNhZ28uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTUwJmNvbnRleHQ9bGF3X2FuZF9lY29ub21pY3Mpe3RhcmdldD0iX2JsYW5rIn0gYXJ0aWNsZS4KCgojICoqTWFpbiBRdWVzdGlvbioqCioqKiAKCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gT3VyIG1haW4gcXVlc3Rpb246IDwvdT48L2I+CgpXaGF0IGlzIHRoZSBlZmZlY3Qgb2YgbXVsdGljb2xsaW5lYXJpdHkgb24gbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzIHdoZW4gYW5hbHl6aW5nIHJpZ2h0IHRvIGNhcnJ5IGxhd3MgYW5kIHZpb2xlbmNlIHJhdGVzPwoKIyMjIwoKU3BlY2lmaWNhbGx5LCB3ZSB3aWxsIGNvbnNpZGVyIHRoZSB0d28gd2F5cyB0byBkZWZpbmUgdGhlIGRlbW9ncmFwaGljIHZhcmlhYmxlcyAoYXMgZGVzY3JpYmVkIGFib3ZlKSBhbmQgaW52ZXN0aWdhdGUgaG93IHRoZSBpbmNsdXNpb24gb2YgZGlmZmVyZW50IG51bWJlcnMgb2YgYWdlIGdyb3VwcyBpbmZsdWVuY2UgdGhlIHJlc3VsdHMgb2YgYW4gYW5hbHlzaXMgb2YgcmlnaHQgdG8gY2FycnkgbGF3cyBhbmQgdmlvbGVuY2UgcmF0ZXMuCgoKIyAqKkxlYXJuaW5nIE9iamVjdGl2ZXMqKiAKKioqIAoKPHU+KipTdGF0aXN0aWNhbCBMZWFybmluZyBPYmplY3RpdmVzOioqPC91PiAKCjEuIFdoYXQgbXVsdGljb2xsaW5lYXJpdHkgaXMgYW5kIGhvdyBpdCBjYW4gaW5mbHVlbmNlIGxpbmVhciByZWdyZXNzaW9uIGNvZWZmaWNpZW50cz8KMi4gSG93IHRvIGxvb2sgZm9yIHRoZSBwcmVzZW5jZSBvZiBtdWx0aWNvbGxpbmFyaXR5IGFuZCBkZXRlcm1pbmUgdGhlIHNldmVyaXR5PwozLiBUaGUgZGlmZmVyZW5jZSBiZXR3ZWVuIG11bHRpY29sbGluZWFyaXR5IGFuZCBjb3JyZWxhdGlvbi4KNC4gSW1wbGVtZW50YXRpb24gb2YgcGFuZWwgcmVncmVzc2lvbiBhbmFseXNpcyAoYHBsbWApLgo1LiBDYWxjdWxhdGlvbiBvZiBWSUYgKGBjYXJgKS4KCjx1PioqRGF0YSBzY2llbmNlIExlYXJuaW5nIE9iamVjdGl2ZXM6Kio8L3U+CgoxLiBEYXRhIGltcG9ydCBvZiBtYW55IGRpZmZlcmVudCBmaWxlIHR5cGVzIHdpdGggc3BlY2lhbCBjYXNlcyAoYHJlYWRyYCwgYHJlYWR4bGAsIGBwZGZ0b29sc2ApLgoyLiBKb2luaW5nIGRhdGEgZnJvbSBtdWx0aXBsZSBzb3VyY2VzIChgZHBseXJgKS4KMy4gV29ya2luZyB3aXRoIGNoYXJhY3RlciBzdHJpbmdzIChgc3RyaW5ncmApLgo0LiBEYXRhIGNvbXBhcmlzb25zIChgZHBseXJgIGFuZCBgamFuaXRvcmApLgo1LiBSZXNoYXBpbmcgZGF0YSBpbnRvIGRpZmZlcmVudCBmb3JtYXRzIChgdGlkeXJgKS4KNi4gRGF0YSB2aXN1YWxpemF0aW9ucyAoYGdncGxvdDJgKS4KNy4gU2FtcGxpbmcgc3Vic2V0cyBvZiBkYXRhIChgcnNhbXBsZWApLgoKCldlIHdpbGwgZXNwZWNpYWxseSBmb2N1cyBvbiB1c2luZyBwYWNrYWdlcyBhbmQgZnVuY3Rpb25zIGZyb20gdGhlIFtgdGlkeXZlcnNlYF0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0sIHN1Y2ggYXMgYGRwbHlyYCBhbmQgYGdncGxvdDJgLiBUaGUgdGlkeXZlcnNlIGlzIGEgbGlicmFyeSBvZiBwYWNrYWdlcyBjcmVhdGVkIGJ5IFJTdHVkaW8uIFdoaWxlIHNvbWUgc3R1ZGVudHMgbWF5IGJlIGZhbWlsaWFyIHdpdGggcHJldmlvdXMgUiBwcm9ncmFtbWluZyBwYWNrYWdlcywgdGhlc2UgcGFja2FnZXMgbWFrZSBkYXRhIHNjaWVuY2UgaW4gUiBlc3BlY2lhbGx5IGVmZmljaWVudC4KCmBgYHtyLCBvdXQud2lkdGggPSAiMjAlIiwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIifQppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3RpZHl2ZXJzZS50aWR5dmVyc2Uub3JnL2xvZ28ucG5nIikKYGBgCgojICoqQ29udGV4dCoqCioqKgoKU28gd2hhdCBleGFjdGx5IGlzIGEgKipyaWdodC10by1jYXJyeSBsYXcqKj8KCkl0IGlzIGEgbGF3IHRoYXQgc3BlY2lmaWVzIF9pZl8gYW5kIF9ob3dfIGNpdGl6ZW5zIGFyZSBhbGxvd2VkIHRvIGhhdmUgYSBmaXJlYXJtIG9uIHRoZWlyIHBlcnNvbiBvciBuZWFyYnkgKGZvciBleGFtcGxlLCBpbiBhIGNpdGl6ZW4ncyBjYXIpIGluIHB1YmxpYy4gCgpUaGUgW1NlY29uZCBBbWVuZG1lbnRdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1NlY29uZF9BbWVuZG1lbnRfdG9fdGhlX1VuaXRlZF9TdGF0ZXNfQ29uc3RpdHV0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9IHRvIHRoZSBVbml0ZWQgU3RhdGVzIENvbnN0aXR1dGlvbiBndWFyYW50ZWVzIHRoZSByaWdodCB0byAia2VlcCBhbmQgYmVhciBhcm1zIi4gVGhlIGFtZW5kbWVudCB3YXMgcmF0aWZpZWQgaW4gMTc5MSBhcyBwYXJ0IG9mIHRoZSBbQmlsbCBvZiBSaWdodHNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1VuaXRlZF9TdGF0ZXNfQmlsbF9vZl9SaWdodHMpe3RhcmdldD0iX2JsYW5rIn0uCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICc1MCUnLCBvdXQud2lkdGggPSAnNTAlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy83Lzc5L0JpbGxfb2ZfUmlnaHRzX1BnMW9mMV9BQy5qcGciKQpgYGAKCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy83Lzc5L0JpbGxfb2ZfUmlnaHRzX1BnMW9mMV9BQy5qcGcpe3RhcmdldD0iX2JsYW5rIn0KCkhvd2V2ZXIsIHRoZXJlIGFyZSBubyBmZWRlcmFsIGxhd3MgYWJvdXQgY2FycnlpbmcgZmlyZWFybXMgaW4gcHVibGljLiAKClRoZXNlIGxhd3MgYXJlIGNyZWF0ZWQgYW5kIGVuZm9yY2VkIGF0IHRoZSBVUyBzdGF0ZSBsZXZlbC4gClN0YXRlcyB2YXJ5IGdyZWF0bHkgaW4gdGhlaXIgbGF3cyBhYm91dCB0aGUgcmlnaHQgdG8gY2FycnkgZmlyZWFybXMuIApTb21lIHJlcXVpcmUgZXh0ZW5zaXZlIGVmZm9ydCB0byBvYnRhaW4gYSBwZXJtaXQgdG8gbGVnYWxseSBjYXJyeSBhIGZpcmVhcm0sIHdoaWxlIG90aGVyIHN0YXRlcyByZXF1aXJlIHZlcnkgbWluaW1hbCBlZmZvcnQgdG8gbGVnYWxseSBjYXJyeSBhIGZpcmVhcm0uCgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gaGlzdG9yeSBvZiByaWdodC10by1jYXJyeSBwb2xpY2llcyBpbiB0aGUgVVMuIDwvc3VtbWFyeT4KCkFjY29yZGluZyB0byBbV2lraXBlZGlhXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9IaXN0b3J5X29mX2NvbmNlYWxlZF9jYXJyeV9pbl90aGVfVS5TLil7dGFyZ2V0PSJfYmxhbmsifSBhYm91dCB0aGUgaGlzdG9yeSBvZiByaWdodC10by1jYXJyeSBwb2xpY2llcyBpbiB0aGUgVW5pdGVkIFN0YXRlczoKCj4gUHVibGljIHBlcmNlcHRpb24gb24gY29uY2VhbGVkIGNhcnJ5IHZzIG9wZW4gY2FycnkgaGFzIGxhcmdlbHkgZmxpcHBlZC4gSW4gdGhlIGVhcmx5IGRheXMgb2YgdGhlIFVuaXRlZCBTdGF0ZXMsIG9wZW4gY2Fycnlpbmcgb2YgZmlyZWFybXMsIGxvbmcgZ3VucyBhbmQgcmV2b2x2ZXJzIHdhcyBhIGNvbW1vbiBhbmQgd2VsbC1hY2NlcHRlZCBwcmFjdGljZS4gU2VlaW5nIGd1bnMgY2FycmllZCBvcGVubHkgd2FzIG5vdCBjb25zaWRlcmVkIHRvIGJlIGFueSBjYXVzZSBmb3IgYWxhcm0uIFRoZXJlZm9yZSwgYW55b25lIHdobyB3b3VsZCBjYXJyeSBhIGZpcmVhcm0gYnV0IGF0dGVtcHQgdG8gY29uY2VhbCBpdCB3YXMgY29uc2lkZXJlZCB0byBoYXZlIHNvbWV0aGluZyB0byBoaWRlLCBhbmQgcHJlc3VtZWQgdG8gYmUgYSBjcmltaW5hbC4gRm9yIHRoaXMgcmVhc29uLCBjb25jZWFsZWQgY2Fycnkgd2FzIGRlbm91bmNlZCBhcyBhIGRldGVzdGFibGUgcHJhY3RpY2UgaW4gdGhlIGVhcmx5IGRheXMgb2YgdGhlIFVuaXRlZCBTdGF0ZXMuCgo+IENvbmNlYWxlZCB3ZWFwb25zIGJhbnMgd2VyZSBwYXNzZWQgaW4gS2VudHVja3kgYW5kIExvdWlzaWFuYSBpbiAxODEzLiAoSW4gdGhvc2UgZGF5cyBvcGVuIGNhcnJ5IG9mIHdlYXBvbnMgZm9yIHNlbGYtZGVmZW5zZSB3YXMgY29uc2lkZXJlZCBhY2NlcHRhYmxlOyBjb25jZWFsZWQgY2Fycnkgd2FzIGRlbm91bmNlZCBhcyB0aGUgcHJhY3RpY2Ugb2YgY3JpbWluYWxzLikgQnkgMTg1OSwgSW5kaWFuYSwgVGVubmVzc2VlLCBWaXJnaW5pYSwgQWxhYmFtYSwgYW5kIE9oaW8gaGFkIGZvbGxvd2VkIHN1aXQuIEJ5IHRoZSBlbmQgb2YgdGhlIG5pbmV0ZWVudGggY2VudHVyeSwgc2ltaWxhciBsYXdzIHdlcmUgcGFzc2VkIGluIHBsYWNlcyBzdWNoIGFzIFRleGFzLCBGbG9yaWRhLCBhbmQgT2tsYWhvbWEsIHdoaWNoIHByb3RlY3RlZCBzb21lIGd1biByaWdodHMgaW4gdGhlaXIgc3RhdGUgY29uc3RpdHV0aW9ucy4gQmVmb3JlIHRoZSBtaWQgMTkwMHMsIG1vc3QgVS5TLiBzdGF0ZXMgaGFkIHBhc3NlZCBjb25jZWFsZWQgY2FycnkgbGF3cyByYXRoZXIgdGhhbiBiYW5uaW5nIHdlYXBvbnMgY29tcGxldGVseS4gVW50aWwgdGhlIGxhdGUgMTk5MHMsIG1hbnkgU291dGhlcm4gc3RhdGVzIHdlcmUgZWl0aGVyICJOby1Jc3N1ZSIgb3IgIlJlc3RyaWN0aXZlIE1heS1Jc3N1ZSIuIFNpbmNlIHRoZW4sIHRoZXNlIHN0YXRlcyBoYXZlIGxhcmdlbHkgZW5hY3RlZCAiU2hhbGwtSXNzdWUiIGxpY2Vuc2luZyBsYXdzLCB3aXRoIG51bWVyb3VzIHN0YXRlcyBsZWdhbGl6aW5nICJVbnJlc3RyaWN0ZWQgY29uY2VhbGVkIGNhcnJ5Ii4KCjwvZGV0YWlscz4KClRoZXJlIGFyZSBmaXZlIGJyb2FkIGNhdGVnb3JpZXMgb2YgcmlnaHQtdG8tY2FycnkgbGF3czoKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQuaGVpZ2h0ID0gJzEwMCUnLCBvdXQud2lkdGggPSAnMTAwJScsIGZpZy5hbGlnbj0nY2VudGVyJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgIlJUQy5wbmciKSkKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3Lm5yYWlsYS5vcmcvZ3VuLWxhd3MvKXt0YXJnZXQ9Il9ibGFuayJ9CgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICcxMDAlJywgb3V0LndpZHRoID0gJzEwMCUnLCBmaWcuYWxpZ249J2NlbnRlcid9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJSVENfbWFwLnBuZyIpKQpgYGAKCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly93d3cubnJhaWxhLm9yZy9ndW4tbGF3cy8pe3RhcmdldD0iX2JsYW5rIn0KCllvdSBjYW4gc2VlIHRoYXQgbm8gc3RhdGUgaW4gdGhlIFVTIGN1cnJlbnRseSBoYXMgYSAiUmlnaHRzIEluZnJpbmdlZC9Ob24tSXNzdWUiIGxhdyAodGhlIGdyYXkgY2F0ZWdvcnkpIC0tIG1lYW5pbmcgdGhhdCBhbGwgNTAgc3RhdGVzIGluIHRoZSBVUyBhbGxvdyB0aGUgcmlnaHQgdG8gY2FycnkgZmlyZWFybXMgYXQgbGVhc3QgaW4gc29tZSB3YXkuIApIb3dldmVyIHRoZSBsZXZlbCBvZiByZXN0cmljdGlvbnMgaXMgZHJhbWF0aWNhbGx5IGRpZmZlcmVudCBmcm9tIG9uZSBzdGF0ZSB0byBhbm90aGVyLgoKCkFWT0NBRE86IEkgcHV0IHRoaXMgbmV4dCBzZWN0aW9uIGluIGEgZGV0YWlscyBjbGlja2FibGUgYm94LiBNeSBzZW5zZSBpcyB0aGF0IHdlIHNob3VsZCBkZWxldGUgdGhpcyBpbmZvcm1hdGlvbiBlbnRpcmVseSBmcm9tIHRoZSBjYXNlIHN0dWR5LCBidXQga2VlcGluZyBpdCBmb3Igbm93IGFuZCB3aWxsIGNvbWUgYmFjayBhbmQgZGVjaWRlIGF0IHRoZSBlbmQgaWYgd2Ugd2FudCB0byBrZWVwIGl0IGFmdGVyIEkgbG9vayB0aHJvdWdoIHRoZSB3aG9sZSB0aGluZy4gCgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gcmlnaHQtdG8tY2FycnkgcG9saWNpZXMgb3ZlciB0aW1lLiA8L3N1bW1hcnk+CgpIZXJlLCB5b3UgY2FuIHNlZSBob3cgdGhlc2UgbGF3cyBoYXZlIGNoYW5nZWQgb3ZlciB0aW1lIGFyb3VuZCB0aGUgY291bnRyeToKYGBge3IsIGVjaG89RkFMU0UsIG91dC5oZWlnaHQgPSAnMTAwJScsIG91dC53aWR0aCA9ICcxMDAlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy90aHVtYi81LzVhL1JpZ2h0X3RvX0NhcnJ5JTJDX3RpbWVsaW5lLmdpZi82MjBweC1SaWdodF90b19DYXJyeSUyQ190aW1lbGluZS5naWYiKQpgYGAKClRoZXJlIGlzIHZhcmlhdGlvbiBmcm9tIHN0YXRlIHRvIHN0YXRlIGV2ZW4gd2l0aGluIHRoZSBzYW1lIGdlbmVyYWwgY2F0ZWdvcnk6CgpGb3IgZXhhbXBsZSBoZXJlIGFyZSB0aGUgW2N1cnJlbnQgY2FycnkgbGF3cyBpbiBJZGFob10oaHR0cHM6Ly93d3cubnJhaWxhLm9yZy9ndW4tbGF3cy9zdGF0ZS1ndW4tbGF3cy9pZGFoby8pIHdoaWNoIGlzIGNvbnNpZGVyZWQgYW4gIlVucmVzdHJpY3RlZCAtIG5vIHBlcm1pdCByZXF1aXJlZCIgc3RhdGU6Cgo+IElkYWhvIHBlcm1pdHMgdGhlIG9wZW4gY2Fycnlpbmcgb2YgZmlyZWFybXMuCgo+IElkYWhvIGxhdyBwZXJtaXRzIGJvdGggcmVzaWRlbnRzIGFuZCBub24tcmVzaWRlbnRzIHdobyBhcmUgYXQgbGVhc3QgMTggeWVhcnMgb2xkIHRvIGNhcnJ5IGNvbmNlYWxlZCB3ZWFwb25zLCB3aXRob3V0IGEgY2FycnkgbGljZW5zZSwgb3V0c2lkZSB0aGUgbGltaXRzIG9mIG9yIGNvbmZpbmVzIG9mIGFueSBjaXR5LCBwcm92aWRlZCB0aGUgcGVyc29uIGlzIG5vdCBvdGhlcndpc2UgZGlzcXVhbGlmaWVkIGZyb20gYmVpbmcgaXNzdWVkIGEgbGljZW5zZSB0byBjYXJyeS4KCj4gQSBwZXJzb24gbWF5IGFsc28gY2FycnkgY29uY2VhbGVkIHdlYXBvbnMgb24gb3IgYWJvdXQgaGlzIG9yIGhlciBwZXJzb24sIHdpdGhvdXQgYSBsaWNlbnNlLCBpbiB0aGUgcGVyc29u4oCZcyBvd24gcGxhY2Ugb2YgYWJvZGUgb3IgZml4ZWQgcGxhY2Ugb2YgYnVzaW5lc3MsIG9uIHByb3BlcnR5IGluIHdoaWNoIHRoZSBwZXJzb24gaGFzIGFueSBvd25lcnNoaXAgb3IgbGVhc2Vob2xkIGludGVyZXN0LCBvciBvbiBwcml2YXRlIHByb3BlcnR5IHdoZXJlIHRoZSBwZXJzb24gaGFzIHBlcm1pc3Npb24gdG8gY2FycnkgZnJvbSBhbnkgcGVyc29uIHdobyBoYXMgYW4gb3duZXJzaGlwIG9yIGxlYXNlaG9sZCBpbnRlcmVzdCBpbiB0aGF0IHByb3BlcnR5LiAKCj4gU3RhdGUgbGF3IGFsc28gYWxsb3dzIGFueSByZXNpZGVudCBvZiBJZGFobyBvciBhIGN1cnJlbnQgbWVtYmVyIG9mIHRoZSBhcm1lZCBmb3JjZXMgb2YgdGhlIFVuaXRlZCBTdGF0ZXMgdG8gY2FycnkgYSBjb25jZWFsZWQgaGFuZGd1biB3aXRob3V0IGEgbGljZW5zZSB0byBjYXJyeSwgcHJvdmlkZWQgdGhlIHBlcnNvbiBpcyBvdmVyIDE4IHllYXJzIG9sZCBhbmQgbm90IGRpc3F1YWxpZmllZCBmcm9tIGJlaW5nIGlzc3VlZCBhIGxpY2Vuc2UgdG8gY2FycnkgY29uY2VhbGVkIHdlYXBvbnMgdW5kZXIgc3RhdGUgbGF3LiBBbiBhbWVuZG1lbnQgdG8gc3RhdGUgbGF3IHRoYXQgdGFrZXMgZWZmZWN0IG9uIEp1bHkgMSwgMjAyMCBjaGFuZ2VzIHRoZSByZWZlcmVuY2UgaW4gdGhlIGFib3ZlIGxhdyBmcm9tIOKAnGEgcmVzaWRlbnQgb2YgSWRhaG/igJ0gdG8g4oCcYW55IGNpdGl6ZW4gb2YgdGhlIFVuaXRlZCBTdGF0ZXMu4oCdICAKCgpBbmQgaGVyZSBhcmUgdGhlIFtjdXJyZW50IGNhcnJ5IGxhd3MgaW4gQXJpem9uYV0oaHR0cHM6Ly93d3cubnJhaWxhLm9yZy9ndW4tbGF3cy9zdGF0ZS1ndW4tbGF3cy9hcml6b25hLykgd2hpY2ggaXMgYWxzbyBjb25zaWRlcmVkIGFuICJVbnJlc3RyaWN0ZWQgLSBubyBwZXJtaXQgcmVxdWlyZWQiIHN0YXRlOgoKPiBBcml6b25hIHJlc3BlY3RzIHRoZSByaWdodCBvZiBsYXcgYWJpZGluZyBjaXRpemVucyB0byBvcGVubHkgY2FycnkgYSBoYW5kZ3VuLgoKPiBBbnkgcGVyc29uIDIxIHllYXJzIG9mIGFnZSBvciBvbGRlciwgd2hvIGlzIG5vdCBwcm9oaWJpdGVkIHBvc3Nlc3NvciwgbWF5IGNhcnJ5IGEgd2VhcG9uIG9wZW5seSBvciBjb25jZWFsZWQgd2l0aG91dCB0aGUgbmVlZCBmb3IgYSBsaWNlbnNlLiBBbnkgcGVyc29uIGNhcnJ5aW5nIHdpdGhvdXQgYSBsaWNlbnNlIG11c3QgYWNrbm93bGVkZ2UgYW5kIGNvbXBseSB3aXRoIHRoZSBkZW1hbmRzIG9mIGEgbGF3IGVuZm9yY2VtZW50IG9mZmljZXIgd2hlbiBhc2tlZCBpZiBoZS9zaGUgaXMgY2FycnlpbmcgYSBjb25jZWFsZWQgZGVhZGx5IHdlYXBvbiwgaWYgdGhlIG9mZmljZXIgaGFzIGluaXRpYXRlZCBhbiAiaW52ZXN0aWdhdGlvbiIgc3VjaCBhcyBhIHRyYWZmaWMgc3RvcC4KCk5vdGljZSB0aGF0IGNpdGl6ZW5zIGluIElkYWhvIG9ubHkgbmVlZCB0byBiZSAxOCB0byBjYXJyeSBhIGZpcmVhcm0sIHdoZXJlYXMgdGhleSBtdXN0IGJlIDIxIGluIEFyaXpvbmEuIAoKCkluIGNvbnRyYXN0LCBoZXJlIGlzIGFuIGV4YW1wbGUgb2YgW2N1cnJlbnQgY2FycnkgbGF3cyBpbiBNYXJ5bGFuZF0oaHR0cHM6Ly93d3cubnJhaWxhLm9yZy9ndW4tbGF3cy9zdGF0ZS1ndW4tbGF3cy9tYXJ5bGFuZC8pIHdoaWNoIGlzIGNvbnNpZGVyZWQgYSAiUmlnaHRzIFJlc3RyaWN0ZWQtVmVyeSBMaW1pdGVkIElzc3VlIiBzdGF0ZToKCj4gQ2FycnlpbmcgYW5kIFRyYW5zcG9ydGF0aW9uIGluIFZlaGljbGVzCkl0IGlzIHVubGF3ZnVsIGZvciBhbnkgcGVyc29uIHdpdGhvdXQgYSBwZXJtaXQgdG8gd2VhciBvciBjYXJyeSBhIGhhbmRndW4sIG9wZW5seSBvciBjb25jZWFsZWQsIHVwb24gb3IgYWJvdXQgaGlzIHBlcnNvbi4gIEl0IGlzIGFsc28gdW5sYXdmdWwgZm9yIGFueSBwZXJzb24gdG8ga25vd2luZ2x5IHRyYW5zcG9ydCBhIGhhbmRndW4gaW4gYW55IHZlaGljbGUgdHJhdmVsaW5nIG9uIHB1YmxpYyByb2FkcywgaGlnaHdheXMsIHdhdGVyd2F5cyBvciBhaXJ3YXlzLCBvciB1cG9uIHJvYWRzIG9yIHBhcmtpbmcgbG90cyBnZW5lcmFsbHkgdXNlZCBieSB0aGUgcHVibGljLiBUaGlzIGRvZXMgbm90IGFwcGx5IHRvIGFueSBwZXJzb24gd2VhcmluZywgY2Fycnlpbmcgb3IgdHJhbnNwb3J0aW5nIGEgaGFuZGd1biB3aXRoaW4gdGhlIGNvbmZpbmVzIG9mIHJlYWwgZXN0YXRlIG93bmVkIG9yIGxlYXNlZCBieSBoaW0sIG9yIG9uIHdoaWNoIGhlIHJlc2lkZXMsIG9yIHdpdGhpbiB0aGUgY29uZmluZXMgb2YgYSBidXNpbmVzcyBlc3RhYmxpc2htZW50IG93bmVkIG9yIGxlYXNlZCBieSBoaW0uCgo+IFBlcm1pdCBUbyBDYXJyeQpBcHBsaWNhdGlvbiBmb3IgYSBwZXJtaXQgdG8gY2FycnkgYSBoYW5kZ3VuIGlzIG1hZGUgdG8gdGhlIFNlY3JldGFyeSBvZiBTdGF0ZSBQb2xpY2UuIEluIGFkZGl0aW9uIHRvIHRoZSBwcmludGVkIGFwcGxpY2F0aW9uIGZvcm0sIHRoZSBhcHBsaWNhbnQgc2hvdWxkIHN1Ym1pdCBhIG5vdGFyaXplZCBsZXR0ZXIgc3RhdGluZyB0aGUgcmVhc29ucyB3aHkgaGUgaXMgYXBwbHlpbmcgZm9yIGEgcGVybWl0LgoKPC9kZXRhaWxzPgoKCiMgKipMaW1pdGF0aW9ucyoqCioqKiAKClRoZXJlIGFyZSBzb21lIGltcG9ydGFudCBjb25zaWRlcmF0aW9ucyByZWdhcmRpbmcgdGhpcyBkYXRhIGFuYWx5c2lzIHRvIGtlZXAgaW4gbWluZDogCgoxLiBXZSBkbyBub3QgdXNlIGFsbCBvZiB0aGUgZGF0YSB1c2VkIGJ5IGVpdGhlciB0aGUgW011c3RhcmQgYW5kIExvdHRdKGh0dHBzOi8vY2hpY2Fnb3VuYm91bmQudWNoaWNhZ28uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTUwJmNvbnRleHQ9bGF3X2FuZF9lY29ub21pY3Mpe3RhcmdldD0iX2JsYW5rIn0gb3IgW0Rvbm9odWUsIGV0IGFsLl0oaHR0cHM6Ly93d3cubmJlci5vcmcvcGFwZXJzL3cyMzUxMC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gYW5hbHlzZXMsIG5vciBkbyB3ZSBwZXJmb3JtIHRoZSBzYW1lIGFuYWx5c2lzIGFzIGluIGVhY2ggYXJ0aWNsZS4gV2UgaW5zdGVhZCBwZXJmb3JtIGEgbXVjaCBzaW1wbGVyIGFuYWx5c2lzIHdpdGggZmV3ZXIgdmFyaWFibGVzIGZvciB0aGUgcHVycG9zZXMgb2YgaWxsdXN0cmF0aW9uIG9mIHRoZSBjb25jZXB0IG9mIG11bHRpY29sbGluZWFyaXR5IGFuZCBpdHMgaW5mbHVlbmNlIG9uIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzLCBub3QgdG8gcmVwcm9kdWNlIGVpdGhlciBhbmFseXNpcy4KCjIuIE91ciBhbmFseXNpcyBhY2NvdW50cyBmb3IgZWl0aGVyIHRoZSBhZG9wdGlvbiBvciBsYWNrIG9mIGFkb3B0aW9uIG9mIGEgcGVybWlzc2l2ZSByaWdodC10by1jYXJyeSBsYXcgaW4gZWFjaCBzdGF0ZSwgYnV0IGRvZXMgbm90IGFjY291bnQgZm9yIGRpZmZlcmVuY2VzIGluIHRoZSBsZXZlbCBvZiBwZXJtaXNzaXZlbmVzcyBvZiB0aGUgbGF3cy4KClJlY2FsbCB0aGF0IHRoZXNlIGFyZSB0aGUgY2F0ZWdvcmllcyBvZiByaWdodCB0byBjYXJyeSBsYXdzOgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICcxMDAlJywgb3V0LndpZHRoID0gJzEwMCUnLCBmaWcuYWxpZ249J2NlbnRlcid9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJSVEMucG5nIikpCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIG91dC5oZWlnaHQgPSAnMTAwJScsIG91dC53aWR0aCA9ICcxMDAlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiUlRDX21hcC5wbmciKSkKYGBgClN0YXRlcyB3aXRoIGxhd3Mgb2YgdGhlIGNhdGVnb3J5IHJpZ2h0cyByZXN0cmljdGVkIC0gdmVyeSBsaW1pdGVkIGlzc3VlIChyZWQpIGFyZSBjb25zaWRlcmVkIGFzIG5vdCBoYXZpbmcgYSBwZXJtaXNzaXZlIHJpZ2h0LXRvLWNhcnJ5IGxhdy4gUmVjYWxsIHRoYXQgbm8gc3RhdGVzIGN1cnJlbnRseSBoYXZlIGEgcmlnaHRzIGluZnJpbmdlZC9ub24taXNzdWUgbGF3LgoKU3RhdGVzIG9mIGFsbCBvdGhlciBjYXRlZ29yaWVzIChzaGFsbCBpc3N1ZSwgZGlzY3JldGlvbmFyeS9yZWFzb25hYmxlIGlzc3VlLCBhbmQgbm8gcGVybWl0IHJlcXVpcmVkKSAoYWxsIHNoYWRlcyBvZiBibHVlKSBhcmUgY29uc2lkZXJlZCB0aGUgc2FtZSBpbiBvdXIgYW5hbHlzaXMsIGFzIGhhdmluZyBhIHBlcm1pc3NpdmUgcmlnaHQtdG8tY2FycnkgbGF3LgoKMykgQmVjYXVzZSBvdXIgYW5hbHlzaXMgaXMgYW4gb3ZlcnNpbXBsaWZpY2F0aW9uLCBvdXIgYW5hbHlzaXMgc2hvdWxkIG5vdCBiZSB1c2VkIGZvciBkZXRlcm1pbmluZyBwb2xpY3kgY2hhbmdlcywgaW5zdGVhZCB3ZSBzdWdnZXN0IHRoYXQgdXNlcnMgY29uc3VsdCB3aXRoIGEgc3BlY2lhbGlzdC4KCmF2b2NhZG8gLSB0aGlzIGlzIGZyb20gTWljaGFlbCBhbmQgdmVyeSBpbXBvcnRhbnQuLi4gbm90IHN1cmUgaG93IHdlIHdhbnQgdG8gd29yZCB0aGlzLi4uCgpJdCBpcyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHdlIGRvIG5vdCB0cmVhdCByYWNlIGFzIGFuIG9iamVjdGl2ZSBtZWFzdXJlLiBEZXNwaXRlIHRoaXMsIGl0IGNhbiBiZSB1c2VkIHRvIGFkdmFuY2Ugc2NpZW50aWZpYyBpbnF1aXJ5LiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB0aGlzIHRvcGljLCB3ZSBoYXZlIGluY2x1ZGVkIGEgbGluayB0byBhIFtwYXBlciBvbiB0aGUgdXNlIG9mIHJhY2UgYXMgYSBtZWFzdXJlIGluIGVwaWRlbWlvbG9neV0oaHR0cHM6Ly9hY2FkZW1pYy5vdXAuY29tL2VwaXJldi9hcnRpY2xlLzIyLzIvMTg3LzQ1Njk0MikuIAoKCldlIHdpbGwgYmVnaW4gYnkgbG9hZGluZyB0aGUgcGFja2FnZXMgdGhhdCB3ZSB3aWxsIG5lZWQ6CgpgYGB7cn0KbGlicmFyeShoZXJlKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShyZWFkcikKbGlicmFyeShwZGZ0b29scykKbGlicmFyeShkcGx5cikKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHB1cnJyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KGNhcikgIyB2aWYgZnVuY3Rpb24KbGlicmFyeShwbG0pICMgZml4ZWQgZWZmZWN0IG1vZGVsLCBsaW5lYXIgcmVncmVzc2lvbgpsaWJyYXJ5KGJyb29tKSAjIHRpZHkgb3V0cHV0CmxpYnJhcnkoY293cGxvdCkgIyB0byBwcm9kdWNlIHBsb3Qgb2YgcGxvdHMgCmxpYnJhcnkoR0dhbGx5KQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGxhdGV4MmV4cCkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KGdnY29ycnBsb3QpCmxpYnJhcnkocnNhbXBsZSkKCnNldC5zZWVkKDk5OSkKYGBgCgoKIFBhY2thZ2UgICB8IFVzZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YQpbcmVhZHhsXShodHRwczovL3JlYWR4bC50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gaW1wb3J0IHRoZSBkYXRhIGluIHRoZSBleGNlbCBmaWxlcyAKW3JlYWRyXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBpbXBvcnQgdGhlIENTViBmaWxlIGRhdGEKW3BkZnRvb2xzXShodHRwczovL2dpdGh1Yi5jb20vcm9wZW5zY2kvcGRmdG9vbHMpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBpbXBvcnQgZGF0YSBmcm9tIGEgcGRmIGZpbGUKW2RwbHlyXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBhcnJhbmdlL2ZpbHRlci9zZWxlY3QvY29tcGFyZSBzcGVjaWZpYyBzdWJzZXRzIG9mIHRoZSBkYXRhICAKW21hZ3JpdHRyXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFncml0dHIvdmlnbmV0dGVzL21hZ3JpdHRyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byB1c2UgdGhlIGNvbXBvdW5kIGFzc2lnbm1lbnQgcGlwZSBvcGVyYXRvciBgJTw+JWAKW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byByZWFycmFuZ2UgZGF0YSBpbiB3aWRlIGFuZCBsb25nIGZvcm1hdHMgCltzdHJpbmdyXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9zdHJpbmdyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBtYW5pcHVsYXRlIHRoZSBjaGFyYWN0ZXIgc3RyaW5ncyB3aXRoaW4gdGhlIGRhdGEgIApbcHVycnJdKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICB8IHRvIGltcG9ydCB0aGUgZGF0YSBpbiBhbGwgdGhlIGRpZmZlcmVudCBleGNlbCBhbmQgY3N2IGZpbGVzIGVmZmljaWVudGx5Cltmb3JjYXRzXShodHRwczovL2ZvcmNhdHMudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBhbGxvdyBmb3IgcmVvcmRlcmluZyBvZiBmYWN0b3JzIGluIHBsb3RzClt0aWJibGVdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICB8IHRvIGNyZWF0ZSBkYXRhIG9iamVjdHMgdGhhdCB3ZSBjYW4gbWFuaXB1bGF0ZSB3aXRoIGBkcGx5cmAvYHN0cmluZ3JgL2B0aWR5cmAvYHB1cnJyYApbY2FyXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvY2FyL3ZpZ25ldHRlcy9lbWJlZGRpbmcucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICB8IHRvIGNhbGN1bGF0ZSBWSUYgdmFsdWVzIG9uIGxpbmVhciBtb2RlbCBvdXRwdXQKW3BsbV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3BsbS92aWduZXR0ZXMvcGxtUGFja2FnZS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gd29yayB3aXRoIHBhbmVsIGRhdGEgZml0dGluZyBmaXhlZCBlZmZlY3RzIGFuZCBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbHMKW2Jyb29tXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvYnJvb20vdmlnbmV0dGVzL2Jyb29tLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBjcmVhdGUgbmljZWx5IGZvcm1hdHRlZCBtb2RlbCBvdXRwdXQKW2Nvd3Bsb3RdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9jb3dwbG90L3ZpZ25ldHRlcy9pbnRyb2R1Y3Rpb24uaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIGFsbG93IHBsb3RzIHRvIGJlIGNvbWJpbmVkIApbR0dhbGx5XShodHRwczovL2dpdGh1Yi5jb20vZ2dvYmkvZ2dhbGx5KXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gZXh0ZW5kIGdncGxvdDIgZnVuY3Rpb25hbGl0eSB0byBlYXNpbHkgY3JlYXRlIG1vcmUgY29tcGxleCBwbG90cwpbZ2dyZXBlbF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dncmVwZWwvdmlnbmV0dGVzL2dncmVwZWwuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIGFsbG93IGxhYmVscyBpbiBmaWd1cmVzIG5vdCB0byBvdmVybGFwCltzY2FsZXNdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9zY2FsZXMvc2NhbGVzLnBkZil7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIGFsbG93IHVzIHRvIGxvb2sgYXQgdGhlIGNvbG9ycyB3aXRoaW4gdGhlIHZpcmlkaXMgcGFja2FnZSBhbmQgdG8gb3ZlcnJpZGUgc29tZSBnZ3Bsb3QyIGRlZmF1bHRzIGZvciBzY2FsZXMgYW5kIGxlZ2VuZHMKW2xhdGV4MmV4cF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2xhdGV4MmV4cC92aWduZXR0ZXMvdXNpbmctbGF0ZXgyZXhwLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBjb252ZXJ0IGxhdGV4IG1hdGggZm9ybXVsYXMgdG8gUidzIHBsb3RtYXRoIGV4cHJlc3Npb25zClt2aXJpZGlzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdmlyaWRpcy92aWduZXR0ZXMvaW50cm8tdG8tdmlyaWRpcy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gbWFrZSBwbG90cyB3aXRoIGEgY29sb3IgcGFsZXR0ZSB0aGF0IGlzIGNvbXBhdGlibGUgd2l0aCBjb2xvciBibGluZG5lc3MKW2dnY29ycnBsb3RdKGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9nZ2NvcnJwbG90L3ZlcnNpb25zLzAuMS4zKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gZWFzaWx5IHZpc3VhbGl6ZSBhIGNvcnJlbGF0aW9uIG1hdHJpeApbcnNhbXBsZV0oaHR0cHM6Ly9yc2FtcGxlLnRpZHltb2RlbHMub3JnKXt0YXJnZXQ9Il9ibGFuayJ9IHwgYSB0aWR5dmVyc2UgcGFja2FnZSBmb3IgZWFzaWx5IHJlc2FtcGxpbmcgZGF0YSAKCgpUaGUgZmlyc3QgdGltZSB3ZSB1c2UgYSBmdW5jdGlvbiwgd2Ugd2lsbCB1c2UgdGhlIGA6OmAgdG8gaW5kaWNhdGUgd2hpY2ggcGFja2FnZSB3ZSBhcmUgdXNpbmcuIFVubGVzcyB3ZSBoYXZlIG92ZXJsYXBwaW5nIGZ1bmN0aW9uIG5hbWVzLCB0aGlzIGlzIG5vdCBuZWNlc3NhcnksIGJ1dCB3ZSB3aWxsIGluY2x1ZGUgaXQgaGVyZSB0byBiZSBpbmZvcm1hdGl2ZSBhYm91dCB3aGVyZSB0aGUgZnVuY3Rpb25zIHdlIHdpbGwgdXNlIGNvbWUgZnJvbS4KCgojICoqV2hhdCBhcmUgdGhlIGRhdGE/KioKKioqCgpCZWxvdyBpcyBhIHRhYmxlIGZyb20gdGhlIFtEb25vaHVlLCBldCBhbC5dKGh0dHBzOi8vd3d3Lm5iZXIub3JnL3BhcGVycy93MjM1MTAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IHBhcGVyIHRoYXQgc2hvd3MgdGhlIGRhdGEgdXNlZCBpbiBib3RoIGFuYWx5c2VzLCB3aGVyZSBEQVcgc3RhbmRzIGZvciBbRG9ub2h1ZSwgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSBhbmQgTE0gc3RhbmRzIGZvciBbTXVzdGFyZCBhbmQgTG90dF0oaHR0cHM6Ly9jaGljYWdvdW5ib3VuZC51Y2hpY2Fnby5lZHUvY2dpL3ZpZXdjb250ZW50LmNnaT9hcnRpY2xlPTExNTAmY29udGV4dD1sYXdfYW5kX2Vjb25vbWljcyl7dGFyZ2V0PSJfYmxhbmsifS4KCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICcxMDAlJywgb3V0LndpZHRoID0gJzEwMCUnLCBmaWcuYWxpZ249J2NlbnRlcid9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJEb25vaHVlX0FwcGVuZGl4Si5wbmciKSkKYGBgCgpXZSB3aWxsIGJlIHVzaW5nIGEgc3Vic2V0IG9mIHRoZXNlIHZhcmlhYmxlcywgd2hpY2ggYXJlIGhpZ2hsaWdodGVkIGluIGdyZWVuOgoKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQuaGVpZ2h0ID0gJzEwMCUnLCBvdXQud2lkdGggPSAnMTAwJScsIGZpZy5hbGlnbj0nY2VudGVyJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgIm91cmRhdGEucG5nIikpCmBgYAoKCiMgKipEYXRhIEltcG9ydCBhbmQgIFdyYW5nbGluZyoqCioqKgphdm9jYWRvOmFkZCBsaW5rIGJlbG93CgpTZWUgW3RoaXMgY2FzZSBzdHVkeV0obmVlZGxpbmspe3RhcmdldD0iX2JsYW5rIn0gZm9yIGRldGFpbHMgYWJvdXQgZGF0YSBpbXBvcnQgYW5kIHdyYW5nbGluZy4KCiMjIERlbW9ncmFwaGljIGFuZCBwb3B1bGF0aW9uIGRhdGEKClRvIG9idGFpbiBpbmZvcm1hdGlvbiBhYm91dCBhZ2UsIHNleCwgYW5kIHJhY2UsIGFuZCBvdmVyYWxsIHBvcHVsYXRpb24gd2Ugd2lsbCB1c2UgVVMgQ2Vuc3VzIEJ1cmVhdSBkYXRhLCBqdXN0IGxpa2UgYm90aCBvZiB0aGUgYXJ0aWNsZXMuIFRoZSBjZW5zdXMgZGF0YSBpcyBhdmFpbGFibGUgZm9yIGRpZmZlcmVudCB0aW1lIHNwYW5zLiBIZXJlIGFyZSB0aGUgbGlua3MgZm9yIHRoZSB5ZWFycyB1c2VkIGluIG91ciBhbmFseXNpcy4gV2Ugd2lsbCB1c2UgZGF0YSBmcm9tIDE5NzcgdG8gMjAxMC4KCkRhdGEgICB8IExpbmsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQoqKnllYXJzIDE5NzcgdG8gMTk3OSoqICB8IFtsaW5rXShodHRwczovL3d3dzIuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL3BvcGVzdC90YWJsZXMvMTkwMC0xOTgwL3N0YXRlL2FzcmgvKSAgCioqeWVhcnMgMTk4MCB0byAxOTg5KiogIHwgW2xpbmtdKGh0dHBzOi8vd3d3Mi5jZW5zdXMuZ292L3Byb2dyYW1zLXN1cnZleXMvcG9wZXN0L3RhYmxlcy8xOTgwLTE5OTAvY291bnRpZXMvYXNyaC8pICogY291bnR5IGRhdGEgd2FzIHVzZWQgZm9yIHRoaXMgZGVjYWRlIHdoaWNoIGFsc28gaGFzIHN0YXRlIGluZm9ybWF0aW9uCioqeWVhcnMgMTk5MCB0byAxOTk5KiogIHwgW2xpbmtdKGh0dHBzOi8vd3d3Mi5jZW5zdXMuZ292L3Byb2dyYW1zLXN1cnZleXMvcG9wZXN0L3RhYmxlcy8xOTkwLTIwMDAvc3RhdGUvYXNyaC8pCioqeWVhcnMgMjAwMCB0byAyMDEwKiogIHwgW2xpbmtdKGh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvZGF0YS9kYXRhc2V0cy90aW1lLXNlcmllcy9kZW1vL3BvcGVzdC9pbnRlcmNlbnNhbC0yMDAwLTIwMTAtc3RhdGUuaHRtbCkgPGJyPiBbdGVjaG5pY2FsIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vd3d3Mi5jZW5zdXMuZ292L3Byb2dyYW1zLXN1cnZleXMvcG9wZXN0L3RlY2huaWNhbC1kb2N1bWVudGF0aW9uL2ZpbGUtbGF5b3V0cy8yMDAwLTIwMTAvaW50ZXJjZW5zYWwvc3RhdGUvc3QtZXN0MDBpbnQtYWxsZGF0YS5wZGYpe3RhcmdldD0iX2JsYW5rIn0KCiMjIFN0YXRlIEZJUFMgY29kZXMKClRoZSAgZGF0YSB3YXMgZG93bmxvYWRlZCBmcm9tIHRoZSBbVVMgQ2Vuc3VzIEJ1cmVhdV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9nZW9ncmFwaGllcy9yZWZlcmVuY2UtZmlsZXMvMjAxNC9kZW1vL3BvcGVzdC8yMDE0LWdlb2NvZGVzLXN0YXRlLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uCgojIyBQb2xpY2Ugc3RhZmZpbmcgZGF0YQoKVGhlIGZvbGxvd2luZyBkYXRhIHdhcyBkb3dubG9hZGVkIGZyb20gdGhlIFtGZWRlcmFsIEJ1cmVhdSBvZiBJbnZlc3RpZ2F0aW9uXShodHRwczovL2NyaW1lLWRhdGEtZXhwbG9yZXIuZnIuY2xvdWQuZ292L2Rvd25sb2Fkcy1hbmQtZG9jcykuIAoKIyMgVW5lbXBsb3ltZW50IGRhdGEKClRoZSBmb2xsb3dpbmcgZGF0YSB3YXMgZG93bmxvYWRlZCBmcm9tIHRoZSBbVS5TLiBCdXJlYXUgb2YgTGFib3IgU3RhdGlzdGljc10oaHR0cHM6Ly9kYXRhLmJscy5nb3YvY2dpLWJpbi9kc3J2P2xhKS4gCgojIyBQb3ZlcnR5IGRhdGEKRXh0cmFjdGVkIGZyb20gVGFibGUgMjEgZnJvbSBbVVMgQ2Vuc3VzIEJ1cmVhdSBQb3ZlcnR5IERhdGEgXShodHRwczovL3d3dy5jZW5zdXMuZ292L2RhdGEvdGFibGVzL3RpbWUtc2VyaWVzL2RlbW8vaW5jb21lLXBvdmVydHkvaGlzdG9yaWNhbC1wb3ZlcnR5LXBlb3BsZS5odG1sKQoKIyMgVmlvbGVudCBjcmltZQoKVmlvbGVudCBjcmltZSBkYXRhIHdhcyBvYnRhaW5lZCBmcm9tIFtoZXJlXShodHRwczovL3d3dy51Y3JkYXRhdG9vbC5nb3YvU2VhcmNoL0NyaW1lL1N0YXRlL1N0YXRlYnlTdGF0ZS5jZm0pLiAKCiMjIFJpZ2h0LXRvLWNhcnJ5IGRhdGEKClRoaXMgZGF0YSBpcyBleHRyYWN0ZWQgZnJvbSB0YWJsZSBpbiBbRG9ub2h1ZSBwYXBlcl0oaHR0cHM6Ly93d3cubmJlci5vcmcvcGFwZXJzL3cyMzUxMC5wZGYpIHt0YXJnZXQ9Il9ibGFuayJ9LiAKCgoKKioqCgpIZXJlIGlzIHRoZSB0YWJsZSBmcm9tIHRoZSBbRG9ub2h1ZSBwYXBlcl0oaHR0cHM6Ly93d3cubmJlci5vcmcvcGFwZXJzL3cyMzUxMC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gdGhhdCBjb21wYXJlcyB0aGUgZGF0YSB1c2VkIGluIHRoZSBhbmFseXNlczoKCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICcxMDAlJywgb3V0LndpZHRoID0gJzEwMCUnLCBmaWcuYWxpZ249J2NlbnRlcid9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsJ0Rvbm9odWVfVGFibGUyX2VkaXRlZC5wbmcnKSkKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3Lm5iZXIub3JnL3BhcGVycy93MjM1MTAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9CgoKIyMjIyMjICpNTCBpcyBhYmJyZXZpYXRlZCBhcyBMTSBpbiB0aGUgc291cmNlIGFydGljbGUKCldlIGNhbiBzZWUgdGhhdCBvbmx5IHRoZSBwZXJjZW50YWdlIG9mIG1hbGVzIHRoYXQgd2VyZSBmcm9tIGFnZSAxNS0zOSBvZiB0aGUgcmFjZSBncm91cHMgKGJsYWNrLCB3aGl0ZSwgYW5kIG90aGVyKSB3ZXJlIHVzZWQgaW4gdGhlIERvbm9odWUgYW5hbHlzaXMuCgpVbHRpbWF0ZWx5IHdlIG1hZGUgYSB0aWJibGUgb2YgZGF0YSB0aGF0IHdhcyBzaW1pbGFyIHRvIGVhY2ggYW5hbHlzaXMuIFdlIHdpbGwgbG9hZCB0aGlzIGRhdGEgbm93LCB3aGljaCBpcyBsb2NhdGVkIGluIHRoZSBgZGF0YWAgZGlyZWN0b3J5LiBXZSBjYW4gdXNlIHRoZSBgaGVyZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGhlcmVgIHBhY2thZ2UgdG8gZWFzaWx5IGxvY2F0ZSBpdC4KCmBgYHtyfQpsb2FkKGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgIldyYW5nbGVkX2RhdGEucmRhIikpCmBgYAoKCldlIHdpbGwgY2hlY2sgdGhlIGRpbWVuc2lvbnMgb2YgZWFjaCB0aWJibGUgdXNpbmcgdGhlIGJhc2UgYGRpbSgpYCBmdW5jdGlvbjoKYGBge3J9CmRpbShMT1RUX0RGKQpkaW0oRE9OT0hVRV9ERikKYGBgCgpBcyBleHBlY3RlZCB0aGUgYExvdHRfREZgIGlzIDMwIGNvbHVtbnMgbGFyZ2VyLCBkdWUgdG8gdGhlIDMwIGFkZGl0aW9uYWwgZGVtb2dyYXBoaWMgdmFyaWFibGVzLiBXZSBjYW4gY2hlY2sgdGhvc2Ugbm93IGFzIHdlbGwuCgpgYGB7cn0KTE9UVF9ERiAlPiUKICAgY29sbmFtZXMoKQoKRE9OT0hVRV9ERiAlPiUKICAgY29sbmFtZXMoKQpgYGAKCkxhc3RseSwgd2Ugd2lsbCBjaGVjayB0aGF0IHRoZSBgWUVBUmAgdmFsdWVzIGFyZSB0aGUgc2FtZS4gV2UgY2FuIHVzZSB0aGUgYHNldGVxdWFsKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gc2VlIGlmIHRoZSB2YWx1ZXMgYXJlIHRoZSBzYW1lLiAKCmBgYHtyfQpzZXRlcXVhbChET05PSFVFX0RGICU+JSBkaXN0aW5jdChZRUFSKSwKICAgICAgICAgIExPVFRfREYgJT4lIGRpc3RpbmN0KFlFQVIpKQpgYGAKCgojICoqRGF0YSBFeHBsb3JhdGlvbioqCioqKgoKIExldCdzIGRvIHNvbWUgcXVpY2sgdmlzdWFsaXphdGlvbnMgdG8gZ2V0IGEgc2Vuc2Ugb2Ygb3VyIG91dGNvbWUgb2YgaW50ZXJlc3QsIHRoZSB2aW9sZW50IGNyaW1lIGRhdGEuIAogCkZpcnN0IHdlIHdpbGwgcGxvdCB0aGUgcmF0ZSBvZiB2aW9sZW50IGNyaW1lIG92ZXIgdGltZSB0byBnZXQgYSBzZW5zZSBvZiB0aGUgZ2VuZXJhbCB0cmVuZC4KClRvIGRvIHNvIHdlIG5lZWQgdG8gc3VtbWFyaXNlIHRoZSBkYXRhIGZvciBlYWNoIHllYXIgYWNyb3NzIGFsbCBvZiB0aGUgc3RhdGVzLiAKVGh1cyB3ZSB3aWxsIHVzZSB0aGUgYGdyb3VwX2J5KClgIGZ1bmN0aW9uIGFuZCB0aGUgYHN1bW1hcmlzZSgpYCBmdW5jdGlvbnMgdG8gY2FsY3VsYXRlIGFuIG92ZXJhbGwgc3VtIG9mIHZpb2xlbnQgY3JpbWUgcmVsYXRpdmUgdG8gdGhlIHBvcHVsYXRpb24gZm9yIGVhY2ggeWVhci4gCgpUaGVuIHdlIHdpbGwgdXNlIHRoZSBgZ2dwbG90MmAgcGFja2FnZSB0byBwbG90IHRoZSBkYXRhLiBUaGUgZmlyc3Qgc3RlcCBpbiBjcmVhdGluZyBhIHBsb3Qgd2l0aCB0aGlzIHBhY2thZ2UgaXMgdG8gdXNlIHRoZSBgZ2dwbG90KClgIGZ1bmN0aW9uIGFuZCB0aGUgYGFlcygpYCBhcmd1bWVudCB0byBzcGVjaWZ5IHdoYXQgZGF0YSBzaG91bGQgYmUgcGxvdHRlZCBvbiB0aGUgeC1heGlzIGFuZCB3aGF0IGRhdGEgc2hvdWxkIGJlIHBsb3R0ZWQgaW4gb24gdGhlIHktYXhpcy4gVGhlbiB3ZSBzZWxlY3Qgd2hhdCB0eXBlIG9mIHBsb3Qgd2Ugd291bGQgbGlrZSB0byBtYWtlIHVzaW5nIG9uZSBvZiB0aGUgYGdlb21fKigpYCBmdW5jdGlvbnMuIFBsZWFzZSBzZWUgW3RoaXMgY2FzZSBzdHVkeV0oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL29jcy1icC1jbzItZW1pc3Npb25zLyl7dGFyZ2V0PSJfYmxhbmsifSAgZm9yIG1vcmUgZGV0YWlscy4KCldlIGNhbiB1c2UgdGhlIGBzY2FsZV94X2NvbnRpbnVvdXMoKWAgYW5kIGBzY2FsZV95X2NvbnRpbnVvdXMoKWAgZnVuY3Rpb25zIHRvICBtb2RpZnkgdGhlIGF4aXMgbGFiZWxzLgoKVGhlIGBsYWJzKClgIGZ1bmN0aW9uIGNhbiBiZSB1c2VkIHRvIGFkZCBsYWJlbHMgdG8gdGhlIHBsb3QsIHdoaWxlIHRoZSBgdGhlbWUoKWAgZnVuY3Rpb24gYWxsb3dzIGZvciBtYW5pcHVsYXRpb24gb2YgdGhlIGRldGFpbHMgb2YgdGhlIGxhYmVscywgbGlrZSBzaXplIGFuZCBhbmdsZS4gCgpBbGwgb2YgdGhlc2UgZnVuY3Rpb25zIGFyZSBwYXJ0IG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4KIApgYGB7cn0KIAogRE9OT0hVRV9ERiAlPiUKICBncm91cF9ieShZRUFSKSAlPiUKICBzdW1tYXJpc2UoVmlvbF9jcmltZV9jb3VudCA9IHN1bShWaW9sX2NyaW1lX2NvdW50KSwKICAgICAgICAgICAgICAgICAgUG9wdWxhdGlvbiA9IHN1bShQb3B1bGF0aW9uKSwKICAgICAgICAgICAgICAgICAgICAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBtdXRhdGUoVmlvbF9jcmltZV9yYXRlXzEwMGtfbG9nID0gbG9nKChWaW9sX2NyaW1lX2NvdW50KjEwMDAwMCkvUG9wdWxhdGlvbikpICU+JQogIGdncGxvdChhZXMoeCA9IFlFQVIsIHkgPSBWaW9sX2NyaW1lX3JhdGVfMTAwa19sb2cpKSArCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTk4MCwgMjAxMCwgYnkgPSAxKSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygxOTgwLCAyMDEwKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhzZXEoMTk4MCwgMjAxMCwgYnkgPSAxKSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDUuNzUsIDYuNzUsIGJ5ID0gMC4yNSksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoNS43NSwgNi43NSkpICsKICBsYWJzKHRpdGxlID0gIkNyaW1lIHJhdGVzIGZsdWN0dWF0ZSBvdmVyIHRpbWUiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHkgPSAibG4odmlvbGVudCBjcmltZXMgcGVyIDEwMCwwMDAgcGVvcGxlKSIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKYGBgCkludGVyZXN0aW5nISBJdCBhcHBlYXJzIHRoYXQgdGhlcmUgd2FzIGFuIG92ZXJhbGwgbmF0aW9uYWwgcGVhayBpbiB2aW9sZW50IGNyaW1lIGluIHRoZSBlYXJseSAxOTkwcyB0aGF0IGhhcyBzaW5jZSB0aGVuIGRlY2xpbmVkLiAgCgoKTm93IGxldCdzIHRha2UgYSBsb29rIGF0IGVhY2ggc3RhdGUuCgpXZSB3aWxsIHVzZSB0aGUgYGdncmVwZWxgIHBhY2thZ2UgdG8gYWRkIHRleHQgdG8gdGhlIHBsb3QgdXNpbmcgdGhlIGBnZW9tX3RleHRfcmVwZWwoKWAgZnVuY3Rpb24uIFRoaXMgaXMgZXNwZWNpYWxseSB1c2VmdWwgd2hlbiB0aGVyZSBpcyBhIGxvdCBvZiB0ZXh0LCBhcyB0aGlzIGZ1bmN0aW9uIHJlZHVjZXMgdGhlIG92ZXJsYXAgb2YgdGV4dCBsYWJlbHMuIEFnYWluIHNlZSBbdGhpcyBjYXNlIHN0dWR5XShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWJwLWNvMi1lbWlzc2lvbnMvKXt0YXJnZXQ9Il9ibGFuayJ9ICBmb3IgbW9yZSBkZXRhaWxzIG9uIGhvdyB0byBhZGQgbGFiZWxzIHRvIGVsZW1lbnRzIG9mIHBsb3RzLgogCmBgYHtyfQoKRE9OT0hVRV9ERiAlPiUKICBtdXRhdGUoVmlvbF9jcmltZV9yYXRlXzEwMGtfbG9nID0gbG9nKChWaW9sX2NyaW1lX2NvdW50KjEwMDAwMCkvUG9wdWxhdGlvbikpICU+JQogIGdncGxvdChhZXMoeCA9IFlFQVIsIHkgPSBWaW9sX2NyaW1lX3JhdGVfMTAwa19sb2csIGNvbG9yID0gU1RBVEUpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArCiAgZ2VvbV9saW5lKGFlcyhncm91cD1TVEFURSksCiAgICAgICAgICAgIHNpemUgPSAwLjUsCiAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IERPTk9IVUVfREYgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKFZpb2xfY3JpbWVfcmF0ZV8xMDBrX2xvZyA9IGxvZygoVmlvbF9jcmltZV9jb3VudCoxMDAwMDApL1BvcHVsYXRpb24pKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoWUVBUiA9PSBsYXN0KFlFQVIpKSwKICAgICAgICAgICAgYWVzKGxhYmVsID0gU1RBVEUsCiAgICAgICAgICAgICAgICB4ID0gWUVBUiwKICAgICAgICAgICAgICAgIHkgPSBWaW9sX2NyaW1lX3JhdGVfMTAwa19sb2cpLAogICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgYWxwaGEgPSAxLAogICAgICAgICAgICBudWRnZV94ID0gMTAsCiAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJ5IiwKICAgICAgICAgICAgaGp1c3QgPSAxLAogICAgICAgICAgICB2anVzdCA9IDEsCiAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMjUsCiAgICAgICAgICAgIHNlZ21lbnQuYWxwaGEgPSAwLjI1LAogICAgICAgICAgICBmb3JjZSA9IDEsCiAgICAgICAgICAgIG1heC5pdGVyID0gOTk5OSkgKwogIGd1aWRlcyhjb2xvciA9IEZBTFNFKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxOTgwLCAyMDE1LCBieSA9IDEpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDE5ODAsIDIwMTUpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKHNlcSgxOTgwLCAyMDEwLCBieSA9IDEpLCByZXAoIiIsIDUpKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMy41LCA4LjUsIGJ5ID0gMC41KSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygzLjUsIDguNSkpICsKICBsYWJzKHRpdGxlID0gIlN0YXRlcyBoYXZlIGRpZmZlcmVudCBsZXZlbHMgb2YgY3JpbWUiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHkgPSAibG4odmlvbGVudCBjcmltZXMgcGVyIDEwMCwwMDAgcGVvcGxlKSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQoKCmBgYAoKTG9va3MgbGlrZSB0aGUgY3JpbWUgcmFnZXMgdmFyeSBxdWl0ZSBhIGJpdCBmcm9tIG9uZSBzdGF0ZSB0byBhbm90aGVyLiBTb21lIHN0YXRlcyBzaG93IGluY3JlYXNlZCBjcmltZSBvdmVyIHRpbWUgd2hpbGUgb3RoZXJzIHNob3cgZGVjcmVhc2VkIGNyaW1lLiAKCgpOb3cgbGV0J3MgdGFrZSBhIGNsb3NlciBsb29rIGF0IHNvbWUgb2Ygb3VyIG90aGVyIHZhcmlhYmxlcy4KCldlIGNhbiBhbHNvIHVzZSB0aGUgYHZpc19taXNzKClgIGZ1bmN0aW9uIG9mIHRoZSBgbmFuaWFyYCBwYWNrYWdlIHRvIGNvbmZpcm0gdGhhdCB0aGVyZSBhcmUgbm8gbWlzc2luZyB2YWx1ZXMuCgpgYGB7cn0KRE9OT0hVRV9ERiAlPiUKICBuYW5pYXI6OnZpc19taXNzKCkKCmBgYAoKTG9va3MgbGlrZSBubyBtaXNzaW5nIGRhdGEhIAoKYGBge3J9CkxPVFRfREYgJT4lCiAgbmFuaWFyOjp2aXNfbWlzcygpCgpgYGAKU2FtZSBmb3IgdGhlIGBMT1RUX0RGYC4KCldlIGNhbiB1c2UgdGhlIGBza2ltKClgIG9mIHRoZSBgc2tpbXJgIHBhY2thZ2UgdG8gZ2V0IGEgYmV0dGVyIHNlbnNlIG9mIHRoZSBkYXRhLiBUaGlzIGFsc28gc2hvd3MgbWlzc2luZ25lc3MsIGFzIHdlbGwgYXMgc3RhbmRhcmQgZGV2aWF0aW9ucywgc3ByZWFkLCBhbmQgbWVhbnMgZm9yIG91ciBkYXRhLiBBbHNvIG5vdGljZSB0aGF0IHRoZXJlIGlzIGEgaGlzdG9ncmFtIG9mIGVhY2ggdmFyaWFibGUuCgpgYGB7cn0Kc2tpbXI6OnNraW0oRE9OT0hVRV9ERikKc2tpbXI6OnNraW0oTE9UVF9ERikKCmBgYApXZSBjYW4gc2VlIGZyb20gdGhpcyBmdW5jdGlvbiwgdGhhdCB3ZSBoYXZlIHRoZSBudW1iZXIgb2YgdmFyaWFibGVzIG9mIHRoZSBjbGFzcyB0eXBlcyB0aGF0IHdlIGV4cGVjdCBmb3IgZWFjaCB0aWJibGUuIFdlIGNhbiBhbHNvIHNlZSB0aGF0IHRoZSBtZWFuIG9mIHRoZSB2YXJpYWJsZXMgdGhhdCBzaG91bGQgYmUgdGhlIHNhbWUgZm9yIGVhY2ggdGliYmxlIGFyZSBpbiBmYWN0IHRoZSBzYW1lLiAKV2UgY2FuIGFsc28gdGVsbCB0aGF0IHRoZSB2YWx1ZXMgZm9yIHRoZSB2YXJpYWJsZXMgYXJlIGluIGdlbmVyYWwgd2hhdCB3ZSB3b3VsZCBleHBlY3QuCgojICoqRGF0YSBBbmFseXNpcyoqCioqKgoKIyMgRG9ub2h1ZSwgZXQgYWwuCgpPSyEgV2UgYXJlIG5vdyByZWFkeSB0byBzdGFydCBhbmFseXppbmcgb3VyIGRhdGEhLiAKCldlIGhhdmUgd2hhdCBpcyBjYWxsZWQgW3BhbmVsIGRhdGFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1BhbmVsX2RhdGEpe3RhcmdldD0iX2JsYW5rIn0gLiBUaGlzIGlzIGEgc3BlY2lhbCB0eXBlIG9mIGxvbmdpdHVkaW5hbCBkYXRhLiBMb25naXR1ZGluYWwgZGF0YSBhcmUgZGF0YSBtZWFzdXJlbWVudHMgdGFrZW4gb3ZlciB0aW1lLiBQYW5lbCBkYXRhIGFyZSBkYXRhIHJlcGVhdGVkbHkgbWVhc3VyZWQgZm9yIGZvciBtdWx0aXBsZSBwYW5lbCBtZW1iZXJzIG9yIGluZGl2aWR1YWxzIG92ZXIgdGltZS4gVGhpcyBpcyBpbiBjb250cmFzdCB3aXRoIHRpbWUgc2VyaWVzIGRhdGEsIHdoaWNoIG1lYXN1cmVzIG9uZSBpbmRpdmlkdWFsIG92ZXIgdGltZSBhbmQgY3Jvc3Mgc2VjdGlvbmFsIGRhdGEsIHdoaWNoIG1lYXN1cmVzIG11bHRpcGxlIGluZGl2aWR1YWxzIGF0IG9uZSBwb2ludCBpbiB0aW1lLiAgSW4gb3RoZXIgd29yZHMsIHBhbmVsIGRhdGEgaXMgYSBjb21iaW5hdGlvbiBvZiBib3RoLCBpbiB0aGlzIGNhc2Ugd2UgbWVhc3VyZSBtdWx0aXBsZSBpbmRpdmlkdWFscyBvdmVyIG11bHRpcGxlIHRpbWUgcGVyaW9kcy4gIEluIG91ciBjYXNlLCB3ZSBoYXZlIG1lYXN1cmVtZW50cyBvZiB2aW9sZW50IGNyaW1lIGFuZCBvdGhlciB2YXJpYWJsZXMgZm9yIGVhY2ggc3RhdGUgb3ZlciBtYW55IHllYXJzLiBUaGVyZWZvcmUgd2UgYXJlIHVzaW5nIG1lYXN1cmVtZW50cyBhYm91dCB0aGUgc2FtZSBzdGF0ZXMgb3ZlciB0aW1lLiAgCgpJbiBhIHBhbmVsIGFuYWx5c2lzIHRoZXJlIGFyZSAkTiQgaW5kaXZpZHVhbCBwYW5lbCBtZW1iZXJzIGFuZCAkVCQgdGltZSBwb2ludHMuICAKClRoZXJlIGFyZSB0d28gdHlwZXMgb2YgcGFuZWxzOiAgCjEuICoqQmFsYW5jZWQqKiAtIEF0IGVhY2ggdGltZSBwb2ludCAoJFQkKSwgdGhlcmUgYXJlIGRhdGEgcG9pbnRzIGZvciBlYWNoIGluZGl2aWR1YWwoJE4kKS4gCgpUaW1lIFBvaW50cyAoJFQkKSAgfCBJbmRpdmlkdWFscyAoJE4kKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQoxOTc3ICB8IE5ldmFkYSAKMTk3NyAgfCBBbGFiYW1hCjE5NzcgIHwgS2Fuc2FzCjE5NzggfCBOZXZhZGEKMTk3OCB8IEFsYWJhbWEKMTk3OCAgfCBLYW5zYXMKMTk3OSB8IE5ldmFkYQoxOTc5IHwgQWxhYmFtYQoxOTc5IHwgS2Fuc2FzCgoyLiAqKlVuYmFsYW5jZWQqKiAtIFRoZXJlIG1heSBiZSBkYXRhIHBvaW50cyBtaXNzaW5nIGZvciBzb21lIGluZGl2aWR1YWxzICgkTiQpIGF0IHNvbWUgdGltZSBwb2ludHMgKCRUJCkuCgpUaW1lIFBvaW50cyAoJFQkKSAgfCBJbmRpdmlkdWFscyAoJE4kKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQoxOTc3ICB8IE5ldmFkYSAKMTk3NyAgfCBBbGFiYW1hCjE5NzggfCBOZXZhZGEKMTk3OCB8IEFsYWJhbWEKMTk3OSB8IE5ldmFkYQoxOTc5IHwgQWxhYmFtYQoxOTc5IHwgS2Fuc2FzCgoKT3ZlcmFsbCBpbiBhIGEgYmFsYW5jZWQgcGFuZWwsIHdlIGhhdmUgJG4kIG9ic2VydmF0aW9ucywgd2hlcmUgJG4gPSBOKlQkLiAgCgpJbiBhbiB1bmJhbGFuY2VkIHBhbmVsLCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpcyBsZXNzIHRoYW4gJE4qVCQuCgoKSW4gb3VyIGNhc2Ugd2UgaGF2ZTogIAokTiQgPSA0NSBzdGF0ZXMgKHJlY2FsbCB0aGF0IHdlIHJlbW92ZWQgdGhvc2Ugd2hvIGhhZCBhZG9wdGVkIGEgUlRDIGxhdyBiZWZvcmUgMTk4MCkgIAokVCQgPSAgMzEgeWVhcnMgKDE5ODAgLSAyMDEwKSAgCgpJbiBldmVyeSB5ZWFyIHdlIGhhdmUgbWVhc3VyZW1lbnRzIGZvciBlYWNoIHN0YXRlIChhcyB3ZSBqdXN0IHNhdyBhYm92ZSksIHRodXMgb3VyIHBhbmVsIGlzIGJhbGFuY2VkLgoKU28sIG91ciB0b3RhbCBvYnNlcnZhdGlvbnMgJG4gPSA0NSozMSQsIHRodXMgJG4kID0gYHIgNDUqMzFgLiAgCgoKCldlIHdpbGwgYmUgcGVyZm9ybWluZyBhICoqcGFuZWwgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgYW5hbHlzaXMqKi4gCgoKSW4gc3VjaCBhbiBhbmFseXNpcyB3ZSB3aWxsIG1vZGVsIG91ciBkYXRhIGFjY29yZGluZyB0byB0aGlzIGdlbmVyaWMgbW9kZWw6CgokJFlfe2l0fT3Osl97MH0rzrJfezF9WF97MWl0fSsuLi4rzrJfe0t9WF97S2l0fSQkCgpXaGVyZSAkaSQgaXMgdGhlIGluZGl2aWR1YWwgZGltZW5zaW9uIChpbiBvdXIgY2FzZSBpbmRpdmlkdWFsIHN0YXRlcykgYW5kICR0JCBpcyB0aGUgdGltZSBkaW1lbnNpb24uCgpTb21lIGV4cGxhbmF0b3J5L2luZGVwZW5kZW50IHZhcmlhYmxlcyBvciByZWdyZXNzb3JzICRYX3tpdH0kIHdpbGwgdmFyeSBhY3Jvc3MgaW5kaXZpZHVhbHMgYW5kIHRpbWUsIHdoaWxlIG90aGVycyB3aWxsIGJlIGZpeGVkIGFjcm9zcyB0aGUgdGltZSBvZiB0aGUgc3R1ZHkgKG9yIGRvbid0IGNoYW5nZSBvdmVyIHRpbWUpLCB3aGlsZSBvdGhlcnMgc3RpbGwgd2lsbCBiZSBmaXhlZCBhY3Jvc3MgaW5kaXZpZHVhbHMgYnV0IHZhcnkgYWNyb3NzIHRpbWUgcGVyaW9kcy4KCgpUaGVyZSBhcmUgdGhyZWUgZ2VuZXJhbCBzdWItdHlwZXMgb2YgW3BhbmVsIHJlZ3Jlc3Npb24gYW5hbHlzaXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1BhbmVsX2FuYWx5c2lzKXt0YXJnZXQ9Il9ibGFuayJ9LgoKT3ZlcmFsbCwgdGhleSBhc3N1bWUgdGhhdCB0aGUgZGlmZmVyZW50IGluZGl2aWR1YWxzIGFyZSBpbmRlcGVuZGVudCwgaG93ZXZlciB0aGUgc2FtZSBkYXRhIGZvciB0aGUgc2FtZSBpbmRpdmlkdWFsIG1heSBiZSBjb3JyZWxhdGVkIGFjcm9zcyB0aW1lLgoKVGhlIG1haW4gZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0aHJlZSBzdWItdHlwZXMgYXJlIHRoZSBhc3N1bXB0aW9ucyBhYm91dCB1bm9ic2VydmVkIGRpZmZlcmVuY2VzIGJldHdlZW4gaW5kaXZpZHVhbHMuCgoKMSkgKippbmRlcGVuZGVudGx5IHBvb2xlZCBwYW5lbHMqKiAgLSBhc3N1bWVzIHRoYXQgdGhlcmUgYXJlIG5vIGluZGl2aWR1YWwgZWZmZWN0cyB0aGF0IGFyZSBpbmRlcGVuZGVudCBvZiB0aW1lIGFuZCBhbHNvIG5vIGVmZmVjdCBvZiB0aW1lIG9uIGFsbCB0aGUgaW5kaXZpZHVhbHMuIEluIG90aGVyIHdvcmRzLCB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzIGFyZSBub3QgY29ycmVsYXRlZCB3aXRoIGFueSBlcnJvciB0ZXJtLiBUaGlzIGlzIGVzc2VudGlhbGx5IGFuIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgbGluZWFyIHJlZ3Jlc3Npb24uIFRoaXMgdHlwZSBvZiBwYW5lbCByZWdyZXNzaW9uIG1ha2VzIHRoZSBtb3N0IGFzc3VtcHRpb25zIGFuZCBpcyB0aGVyZWZvcmUgdHlwaWNhbGx5IG5vdCB1c2VkIGZvciBwYW5lbCBkYXRhLgoKICQkWV97aXR9PVxiZXRhX3swfStcYmV0YV97MX14X3sxaXR9Ky4uLitcYmV0YV9fS1hfe0tpdH0gKyBlX3tpdH0kJApXaGVyZSB0aGUgaW50ZXJjZXB0ICRcYmV0YV8waXQ9XGJldGFfMCRmb3IgYWxsICRpLHQkIGFuZCBzbG9wZSAkXGJldGFfa2l0PVxiZXRhX2skIGZvciBhbGwgJGksdCQuCgoyKSAqKmZpeGVkIGVmZmVjdHMqKiAtIGFzc3VtZXMgdGhhdCB0aGVyZSBhcmUgdW5rbm93biBvciB1bm9ic2VydmVkIHVuaXF1ZSBhc3BlY3RzIGFib3V0IHRoZSBpbmRpdmlkdWFscyAgb3IgaGV0ZXJvZ2VuZWl0eSBhbW9uZyBpbmRpdmlkdWFscyAkQl8waSQgdGhhdCBhcmUgbm90IGV4cGxhaW5lZCBieSB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzIGJ1dCBpbmZsdWVuY2UgdGhlIG91dGNvbWUgdmFyaWFibGUgb2YgaW50ZXJlc3QuIFRoZXkgZG8gbm90IHZhcnkgd2l0aCB0aW1lIG9yIGluIG90aGVyIHdvcmRzIGFyZSBmaXhlZCBvdmVyIHRpbWUgYnV0IG1heSBiZSAqKmNvcnJlbGF0ZWQqKiB3aXRoIGluZGVwZW5kZW50IHZhcmlhYmxlcyAkWF97aXR9JC4gIAoKSW4gdGhpcyBjYXNlIHRoZSBpbnRlcmNlcHQgY2FuIGJlIGRpZmZlcmVudCBmb3IgZWFjaCBpbmRpdmlkdWFsICRcYmV0YV97MGl9JCwgYnV0IHRoZSBzbG9wZSBpcyB0aGUgc2FtZSBhY3Jvc3MgYWxsIHRoZSBpbmRpdmlkdWFscy4KCgpUaGVzZSBpbmRpdmlkdWFsICRhX2kkIGVmZmVjdHMgY2FuIGJlIGNvcnJlbGF0ZWQgd2l0aCB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzICRYJC4KCiQkWV97aXR9PVxiZXRhX3swaX0rXGJldGFfezF9WF97MWl0fSsuLi5cYmV0YV97a31YX3traXR9K2VfaXQkJApUaGlzIHR5cGUgb2YgcGFuZWwgcmVncmVzc2lvbiBtYWtlcyB0aGUgbGVhc3QgYXNzdW1wdGlvbnMuCgoKMykgKipyYW5kb20gZWZmZWN0cyoqIC0gYXNzdW1lcyB0aGF0IHRoZXJlIGFyZSB1bmtub3duIG9yIHVub2JzZXJ2ZWQgdW5pcXVlIHF1YWxpdGllcyBhYm91dCB0aGUgaW5kaXZpZHVhbHMgdGhhdCBpbmZsdWVuY2VzIHRoZSBvdXRjb21lIHZhcmlhYmxlIG9mIGludGVyZXN0IHRoYXQgYXJlICoqbm90IGNvcnJlbGF0ZWQqKiB3aXRoIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMuIAoKVGh1cywgdGhlIHJhbmRvbSBlZmZlY3RzIG1vZGVsIGFjdHVhbGx5IG1ha2VzICoqbW9yZSBhc3N1bXB0aW9ucyoqIHRoYW4gdGhlIGZpeGVkIGVmZmVjdCBtb2RlbC4KCiQkWV97aXR9ID1cYmV0YV8wIFhfe2l0fSArXGJldGFfezF9WF97MWl0fSsuLi4gXGJldGFfayBYX3trdH0gKyBlX3t0fSQkClNvIGVhY2ggaW5kaXZpZHVhbCBoYXMgdGhlIHNhbWUgc2xvcGUgYW5kIHRoZSBzYW1lIG92ZXJhbGwgZXJyb3IgdGVybSAoJFxiZXRhICsgZV97dH0kKS4gCgoKU2VlIFtoZXJlXShodHRwczovL3d3dy5iYXVlci51aC5lZHUvcnN1c21lbC9waGQvZWMxLTE1LnBkZikgYW5kIFtoZXJlXShodHRwczovL3NpdGVzLmdvb2dsZS5jb20vc2l0ZS9lY29ub21ldHJpY3NhY2FkZW15L2Vjb25vbWV0cmljcy1tb2RlbHMvcGFuZWwtZGF0YS1tb2RlbHMpIGFuZCBbaGVyZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3BsbS92aWduZXR0ZXMvcGxtUGFja2FnZS5odG0pIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHRoZXNlIGRpZmZlcmVudCBtb2RlbHMuCgpXZSB3aWxsIGJlIHBlcmZvcm1pbmcgYSBmaXhlZCBlZmZlY3QgcGFuZWwgcmVncmVzc2lvbiBhbmFseXNpcywgYXMgd2UgZG8gaW4gZmFjdCB0aGluayB0aGF0IHNvbWUgb2YgdGhlIHVub2JzZXJ2ZWQgcXVhbGl0aWVzIGFib3V0IHRoZSBkaWZmZXJlbnQgc3RhdGVzIHRoYXQgbWF5IGJlIGNvcnJlbGF0ZWQgd2l0aCBzb21lIG9mIG91ciBpbmRlcGVuZGVudCB2YXJpYWJsZXMuIEZvciBleGFtcGxlLCB0aGUgbGV2ZWwgb2YgZWNvbm9taWMgb3Bwb3J0dW5pdHkgbWlnaHQgYmUgYW4gdW5vYnNlcnZlZCBmZWF0dXJlIGFib3V0IHRoZSBzdGF0ZXMgdGhhdCBpbmZsdWVuY2VzIHZpb2xlbnQgY3JpbWUgcmF0ZSBhbmQgd291bGQgYmUgcG9zc2libHkgY29ycmVsYXRlZCB3aXRoIHBvdmVydHkgcmF0ZSBhbmQgdW5lbXBsb3ltZW50LiAKCgpUbyBwZXJmb3JtIG91ciBhbmFseXNpcyB3ZSB3aWxsIGJlIHVzaW5nIHRoZSBgcGxtYCBwYWNrYWdlLiBUaGlzIHN0YW5kcyBmb3IgUGFuZWwgTGluZWFyIE1vZGVsLgoKV2UgbmVlZCB0byB1c2UgYSBzcGVjaWFsIHR5cGUgb2YgZGF0YSB0byB1c2UgdGhpcyBwYWNrYWdlLCBjYWxsZWQgYSBgcGRhdGEuZnJhbWVgIHdoaWNoIGlzIHNob3J0IGZvciBwYW5lbCBkYXRhIGZyYW1lLiBUaGlzIGFsbG93cyB1cyB0byBzcGVjaWZ5IHRoYXQgd2UgYXJlIHVzaW5nIHBhbmVsIGRhdGEgYW5kIHdoYXQgdGhlIHBhbmVsIHN0cnVjdHVyZSBsb29rcyBsaWtlLiAKCldlIG5lZWQgdG8gaW5kaWNhdGUgdmFyaWFibGUgc2hvdWxkIGJlIHVzZWQgdG8gaWRlbnRpZnkgdGhlIGluZGl2aWR1YWxzIGluIG91ciBwYW5lbCwgYW5kIHdoYXQgdmFyaWFibGUgc2hvdWxkIGJlIHVzZWQgdG8gaWRlbnRpZnkgdGhlIHRpbWUgcGVyaW9kcyBpbiBvdXIgcGFuZWwuIEluIG91ciBjYXNlIHRoZSBgU1RBVEVgIHZhcmlhYmxlIGlkZW50aWZpZXMgdGhlIGluZGl2aWR1YWxzIGFuZCB0aGUgYFlFQVJgIHZhcmlhYmxlIGlkZW50aWZpZXMgdGhlIHRpbWUgcGVyaW9kcy4KCldlIGNhbiBzcGVjaWZ5IHRoaXMgc3RydWN0dXJlIHVzaW5nIHRoZSBgcGRhdGEuZnJhbWUoKWAgZnVuY3Rpb24gb2YgdGhlIGBwbG1gIHBhY2thZ2UsIGJ5IHVzaW5nIHRoZSBgaW5kZXhgIGFyZ3VtZW50LCB3aGVyZSB0aGUgaW5kaXZpZHVhbCB2YXJpYWJsZSBpcyBzcGVjaWZpZWQgZmlyc3QgZm9sbG93ZWQgYnkgdGhlIHRpbWUgdmFyaWFibGUsIGxpa2Ugc286IGBpbmRleD1jKCJJbmRpdmlkdWFsX1ZhcmlhYmxlX05BTUUiLCAiVGltZV9QZXJpb2RfVmFyaWFibGVfTkFNRSIpLgoKYGBge3J9CmRfcGFuZWxfRE9OT0hVRSA8LSBwZGF0YS5mcmFtZShET05PSFVFX0RGLCBpbmRleD1jKCJTVEFURSIsICJZRUFSIikpCgpjbGFzcyhkX3BhbmVsX0RPTk9IVUUpCgpzbGljZV9oZWFkKGRfcGFuZWxfRE9OT0hVRSwgbiA9IDMpCmBgYAoKSW5kZWVkIHdlIGhhdmUgbm93IGNyZWF0ZWQgYSBwZGF0YS5mcmFtZSBvYmplY3QgYW5kIHdlIGNhbiBzZWUgdGhhdCB0aGUgcm93IG5hbWVzIHNob3cgdGhlIGluZGl2aWR1YWwgc3RhdGVzIGFuZCB0aW1lIHBlcmlvZCB5ZWFycy4KCk9LLCBub3cgd2UgYXJlIHJlYWR5IHRvIHJ1biBvdXIgcGFuZWwgbGluZWFyIG1vZGVsIG9uIG91ciBwYW5lbCBkYXRhIGZyYW1lLiAKClRvIGRvIHNvIHdlIHdpbGwgdXNlIHRoZSBgcGxtKClgIGZ1bmN0aW9uIGFuZCB3ZSB3aWxsIHNwZWNpZnkgdGhlIGZvcm11bGEgZm9yIG91ciBtb2RlbCwgd2hlcmUgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBgVmlvbF9jcmltZV9yYXRlXzFrX2xvZ2Agd2lsbCBiZSBvbiB0aGUgbGVmdCBvZiBvdXIgYH5gIHNpZ24gYW5kIGFsbCBvZiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzIHdpbGwgYmUgbGlzdGVkIG9uIHRoZSByaWdodCB3aXRoIGArYCBzaWducyBpbiBiZXR3ZWVuIGVhY2guCgpXZSBhbHNvIG5lZWQgdG8gc3BlY2lmeSB3aGF0IHR5cGUgb2YgYGVmZmVjdGAgd2Ugd291bGQgbGlrZSB0byBtb2RlbCBhbmQgd2hhdCB0eXBlIG9mIGBtb2RlbGAgd2Ugd291bGQgbGlrZSB0byB1c2UuCgpUaGVyZSBhcmUgdGhyZWUgbWFpbiBvcHRpb25zIGZvciB0aGUgYGVmZmVjdGAgYXJndW1lbnQ6CjEpIGluZGl2aWR1YWwgIC0gbW9kZWwgZm9yIHRoZSBlZmZlY3Qgb2YgaW5kaXZpZHVhbCBpZGVudGl0eQoyKSB0aW1lIC0gbW9kZWwgZm9yIHRoZSBlZmZlY3Qgb2YgdGltZQozKSB0d293YXlzIC0gbWVhbmluZyBtb2RlbGluZyBmb3IgdGhlIGVmZmVjdCBvZiBib3RoIGluZGl2aWR1YWwgaWRlbnRpdHkgYW5kIHRpbWUgIAoKVGhlcmUgYXJlIGZvdXIgbWFpbiBvcHRpb25zIGZvciB0aGUgYG1vZGVsYCBhcmd1bWVudDogIAoxKSBwb29saW5nIC0gc3RhbmRhcmQgcG9vbGVkIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgcmVncmVzc2lvbiBtb2RlbCAgCjIpIHdpdGhpbiAtIGZpeGVkIGVmZmVjdHMgbW9kZWwgKHZhcmlhdGlvbiBiZXR3ZWVuIGluZGl2aWR1YWxzIGlzIGlnbm9yZWQsIG1vZGVsIGNvbXBhcmVzIGluZGl2aWR1YWxzIHRvIHRoZW1zZWx2ZXMgYXQgZGlmZmVyZW50IHBlcmlvZHMgb2YgdGltZSkgIAozKSBiZXR3ZWVuIC0gZml4ZWQgZWZmZWN0cyBtb2RlbCAodmFyaWF0aW9uIHdpdGhpbiBpbmRpdmlkdWFscyBmcm9tIG9uZSB0aW1lIHBvaW50IHRvIGFub3RoZXIgaXMgaWdub3JlZCwgbW9kZWwgY29tcGFyZXMgZGlmZmVyZW50IGluZGl2aWR1YWxzIGF0IGVhY2ggcG9pbnQgb2YgdGltZSkgIAo0KSByYW5kb20gLSByYW5kb20gZWZmZWN0cyAoZWFjaCBzdGF0ZSBoYXMgYSBkaWZmZXJlbnQgaW50ZXJjZXB0IGJ1dCBmb3JjZSBpdCB0byBmb2xsb3cgYSBub3JtYWwgZGlzdHJpYnV0aW9uIC0gcmVxdWlyZXMgbW9yZSBhc3N1bXB0aW9ucykKClR5cGljYWxseSBpdCBpcyBiZXN0IHRvIHRoaW5rIGFib3V0IHdoYXQgeW91IGFyZSB0cnlpbmcgdG8gZXZhbHVhdGUgd2l0aCB5b3VyIGRhdGEgaW4gdHJ5aW5nIHRvIGNob29zZSBob3cgdG8gbW9kZWwgeW91ciBkYXRhLiBIb3dldmVyLCB0aGVyZSBhcmUgYWxzbyBzb21lIHRlc3RzIHRoYXQgY2FuIGhlbHAgdG8gYXNzZXNzIHRoaXMgd2hpY2ggd2Ugd2lsbCBicmllZmx5IGNvdmVyLgoKV2UgYXJlIGludGVyZXN0ZWQgaW4gaG93IHZpb2xlbmNlIGluIGVhY2ggc3RhdGUgdmFyaWVkIG92ZXIgdGltZSwgdGh1cyB3ZSBhcmUgaW50ZXJlc3RlZCBpbiB3aXRoaW4gYFNUQVRFYHZhcmlhdGlvbiwgc28gd2Ugd2lsbCBwZXJmb3JtIG91ciBwbG0gd2l0aCB0aGUgYG1vZGVsID0gd2l0aGluYCBhcmd1bWVudCB0byBwZXJmb3JtIHRoaXMgcGFydGljdWxhciB0eXBlIG9mIGZpeGVkIGVmZmVjdHMgbW9kZWwuIAoKV2UgYWxzbyBzcGVjdWxhdGUgdGhhdCB0aGVyZSBpcyBhbiBlZmZlY3Qgb2YgaW5kaXZpZHVhbCBgU1RBVEVgIGlkZW50aXR5IGFuZCB0aW1lIG9uIHZpb2xlbnQgY3JpbWUgcmF0ZS4gSW4gb3RoZXIgd29yZHMsIHdlIGV4cGVjdCBzb21lIHN0YXRlcyB0byBoYXZlIGhpZ2ggcmF0ZXMgb2YgY3JpbWUsIGFuZCBvdGhlcnMgdG8gaGF2ZSBsb3cgcmF0ZXMgb2YgY3JpbWUuIFdlIGFsc28gZXhwZWN0IGNyaW1lIHRvIGNoYW5nZSBvdmVyIHRpbWUuIAoKSWYgd2Ugd2VyZSB0byBwZXJmb3JtIHRoaXMgdHlwZSBvZiBhbmFseXNpcyB3ZSB3b3VsZCB1c2UgdGhlIGBlZmZlY3QgPSAidHdvd2F5cyJgIGFyZ3VtZW50IGluIG91ciBgcGxtKClgIGZ1bmN0aW9uIGxpa2Ugc286CgpgYGB7cn0KRE9OT0hVRV9PVVRQVVQgPC0gcGxtKFZpb2xfY3JpbWVfcmF0ZV8xa19sb2cgfgogICAgICAgICAgICAgICAgICAgICAgICBSVENfTEFXICsKICAgICAgICAgICAgICAgICAgICAgICAgV2hpdGVfTWFsZV8xNV90b18xOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIFdoaXRlX01hbGVfMjBfdG9fMzlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBCbGFja19NYWxlXzE1X3RvXzE5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgQmxhY2tfTWFsZV8yMF90b18zOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIE90aGVyX01hbGVfMTVfdG9fMTlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBPdGhlcl9NYWxlXzIwX3RvXzM5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgVW5lbXBsb3ltZW50X3JhdGUgKwogICAgICAgICAgICAgICAgICAgICAgICBQb3ZlcnR5X3JhdGUgKyAKICAgICAgICAgICAgICAgICAgICAgICAgUG9wdWxhdGlvbl9sb2cgKyAKICAgICAgICAgICAgICAgICAgICAgICAgcG9saWNlX3Blcl8xMDBrX2xhZywKICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0ID0gInR3b3dheXMiLAogICAgICAgICAgICAgICAgICAgICAgICBtb2RlbCA9ICJ3aXRoaW4iLAogICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gZF9wYW5lbF9ET05PSFVFKQpgYGAKClRvIHNlZSB0aGUgcmVzdWx0cyB3ZSBjYW4gdXNlIHRoZSBiYXNlIGBzdW1tYXJ5KClgIGZ1bmN0aW9uLiBXZSBjYW4gdmlldyB0aGlzIG91dHB1dCBpbiB0aWR5IGZvcm1hdCB1c2luZyB0aGUgYHRpZHkoKWAgZnVuY3Rpb24gb2YgdGhlIGBicm9vbWAgcGFja2FnZS4KCldlIHdpbGwgYWRkIGFuIGBhbmFseXNpc2AgdmFyaWFibGUgaXMgYSBsYWJlbCBmb3IgcGxvdHMuCgpgYGB7cn0Kc3VtbWFyeShET05PSFVFX09VVFBVVCkKCkRPTk9IVUVfT1VUUFVUX1RJRFkgPC0gdGlkeShET05PSFVFX09VVFBVVCwgY29uZi5pbnQgPSAwLjk1KQoKRE9OT0hVRV9PVVRQVVRfVElEWQoKRE9OT0hVRV9PVVRQVVRfVElEWSRBbmFseXNpcyA8LSAiQW5hbHlzaXMgMSIKYGBgCgpXZSB3aWxsIG5vdyBwZXJmb3JtIGEgdGVzdCB0byBkZXRlcm1pbmUgaWYgd2UgY291bGQgaGF2ZSBzaW1wbHkgdXNlZCBhIHBvb2xlZCBtb2RlbC4gVGhpcyB0ZXN0IGV2YWx1YXRlcyBpZiB0aGUgY29lZmZpY2llbnRzIChpbmNsdWRpbmcgdGhlIGludGVyY2VwdHMpIGFyZSBlcXVhbC4gIFRvIHBlcmZvcm0gdGhpcyB0ZXN0IHdlIHdpbGwgdXNlIHRoZSBgcG9vbHRlc3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBwbG1gIHBhY2thZ2UgdG8gY29tcGFyZSB0aGUgcG9vbGVkIG1vZGVsIHRvIHRoZSBmaXhlZCBlZmZlY3Qgd2l0aGluIG1vZGVsLgoKYGBge3J9CnBvb2x0ZXN0KFZpb2xfY3JpbWVfcmF0ZV8xa19sb2cgfgogICAgICAgICAgICAgICAgICAgICAgICBSVENfTEFXICsKICAgICAgICAgICAgICAgICAgICAgICAgV2hpdGVfTWFsZV8xNV90b18xOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIFdoaXRlX01hbGVfMjBfdG9fMzlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBCbGFja19NYWxlXzE1X3RvXzE5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgQmxhY2tfTWFsZV8yMF90b18zOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIE90aGVyX01hbGVfMTVfdG9fMTlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBPdGhlcl9NYWxlXzIwX3RvXzM5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgVW5lbXBsb3ltZW50X3JhdGUgKwogICAgICAgICAgICAgICAgICAgICAgICBQb3ZlcnR5X3JhdGUgKyAKICAgICAgICAgICAgICAgICAgICAgICAgUG9wdWxhdGlvbl9sb2cgKyAKICAgICAgICAgICAgICAgICAgICAgICAgcG9saWNlX3Blcl8xMDBrX2xhZywgCiAgICAgICAgIGRhdGEgPSBkX3BhbmVsX0RPTk9IVUUsIAogICAgICAgICBtb2RlbCA9ICJ3aXRoaW4iKQoKYGBgCgpUaGUgYHAtdmFsdWVgIGlzIGxlc3MgdGhhbiBhIHNpZ25pZmljYW5jZSB0aHJlc2hvbGQgb2YgLjA1LCB0aHVzIHdlIHJlamVjdCB0aGUgbnVsbCB0aGF0IG91ciBjb2VmZmljaWVudHMgYXJlIGFsbCBlcXVhbC4gVGh1cyB0aGUgYHdpdGhpbmAgZml4ZWQgZWZmZWN0cyBtb2RlbCBmaXQgdGhlIGRhdGEgYmV0dGVyLgoKCldlIGNhbiBhbHNvIHBlcmZvcm0gYSB0ZXN0IHRvIGV2YWx1YXRlIGlmIHRoZXJlIGlzIGluZGVlZCBhbiBpbmRpdmlkdWFsIGVmZmVjdCBhbmQgYSB0aW1lIGVmZmVjdCBpbiBvdXIgbW9kZWwuCgpXZSBjYW4gdXNlIHRoZSBgcGxtdGVzdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHBsbWAgcGFja2FnZS4gVGhpcyBwZXJmb3JtcyBhIExhZ3JhbmdlIE11bHRpcGxpZXIgVGVzdC4gVG8gZG8gc28sIHdlIG5lZWQgdG8gZ2V0IHRoZSBvdXRwdXQgZm9yIGEgc2ltcGxlIHBvb2xlZCBtb2RlbC4KCmBgYHtyfQoKRE9OT0hVRV9wb29sX21vZGVsIDwtcGxtKFZpb2xfY3JpbWVfcmF0ZV8xa19sb2cgfgogICAgICAgICAgICAgICAgICAgICAgICBSVENfTEFXICsKICAgICAgICAgICAgICAgICAgICAgICAgV2hpdGVfTWFsZV8xNV90b18xOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIFdoaXRlX01hbGVfMjBfdG9fMzlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBCbGFja19NYWxlXzE1X3RvXzE5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgQmxhY2tfTWFsZV8yMF90b18zOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIE90aGVyX01hbGVfMTVfdG9fMTlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBPdGhlcl9NYWxlXzIwX3RvXzM5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgVW5lbXBsb3ltZW50X3JhdGUgKwogICAgICAgICAgICAgICAgICAgICAgICBQb3ZlcnR5X3JhdGUgKyAKICAgICAgICAgICAgICAgICAgICAgICAgUG9wdWxhdGlvbl9sb2cgKyAKICAgICAgICAgICAgICAgICAgICAgICAgcG9saWNlX3Blcl8xMDBrX2xhZywKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSAicG9vbGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZF9wYW5lbF9ET05PSFVFKQoKcGxtdGVzdChET05PSFVFX3Bvb2xfbW9kZWwsIGVmZmVjdCA9IGMoInR3b3dheXMiKSkKCmBgYAoKQWdhaW4sIHRoZSBwLXZhbHVlIGlzIG11Y2ggc21hbGxlciB0aGFuIHRoZSBzaWduaWZpY2FuY2UgdGhyZXNob2xkIG9mIDwgMC4wNS4gVGhlcmVmb3JlIHdlIHJlamVjdCB0aGUgbnVsbCB0aGF0IHRoZXJlIGFyZSBubyBlZmZlY3RzLCBhbmQgd2UgY2FuIGZlZWwgY29uZmlkZW50IHdpdGggcHJvY2VlZGluZyB3aXRoIGEgdHdvd2F5IGVmZmVjdCBtb2RlbC4KCgoKCgpUaGVyZSBpcyBvbmUgbW9yZSB0ZXN0IHRoYXQgd2UgY291bGQgcGVyZm9ybS4gVG8gdGVzdCBpZiB1c2luZyBhIHJhbmRvbSBlZmZlY3QgbW9kZWwgd291bGQgYmUgbW9yZSBhcHByb3ByaWF0ZSBjb21wYXJlZCB0byB0aGUgZml4ZWQgZWZmZWN0IG1vZGVsLCBvbmUgY291bGQgdXNlIHRoZSBbSGF1c21lbiB0ZXN0XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EdXJiaW4lRTIlODAlOTNXdSVFMiU4MCU5M0hhdXNtYW5fdGVzdCl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgdGhpcyAoYWxzbyBjYWxsZWQgdGhlIER1cmJpbi1XdS1IYXVzbWFuIHRlc3QpLiBUaGlzIGNhbiBiZSBpbXBsZW1lbnRlZCB1c2luZyB0aGUgYHBodGVzdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHBsbWAgcGFja2FnZS4KCmBgYHtyfQoKRE9OT0hVRV9yYW5kb21fbW9kZWwgPC0gIHBsbShWaW9sX2NyaW1lX3JhdGVfMWtfbG9nIH4KICAgICAgICAgICAgICAgICAgICAgICAgUlRDX0xBVyArCiAgICAgICAgICAgICAgICAgICAgICAgIFdoaXRlX01hbGVfMTVfdG9fMTlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBXaGl0ZV9NYWxlXzIwX3RvXzM5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgQmxhY2tfTWFsZV8xNV90b18xOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIEJsYWNrX01hbGVfMjBfdG9fMzlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBPdGhlcl9NYWxlXzE1X3RvXzE5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgT3RoZXJfTWFsZV8yMF90b18zOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIFVuZW1wbG95bWVudF9yYXRlICsKICAgICAgICAgICAgICAgICAgICAgICAgUG92ZXJ0eV9yYXRlICsgCiAgICAgICAgICAgICAgICAgICAgICAgIFBvcHVsYXRpb25fbG9nICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHBvbGljZV9wZXJfMTAwa19sYWcsCiAgICAgICAgICAgICAgICAgICAgICBlZmZlY3QgPSAidHdvd2F5cyIsCiAgICAgICAgICAgICAgICAgICAgICBtb2RlbCA9ICJyYW5kb20iLAogICAgICAgICAgICAgICAgICAgICAgZGF0YT1kX3BhbmVsX0RPTk9IVUUpCgpET05PSFVFX3dpdGhpbl9tb2RlbCA8LSAgcGxtKFZpb2xfY3JpbWVfcmF0ZV8xa19sb2cgfgogICAgICAgICAgICAgICAgICAgICAgICBSVENfTEFXICsKICAgICAgICAgICAgICAgICAgICAgICAgV2hpdGVfTWFsZV8xNV90b18xOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIFdoaXRlX01hbGVfMjBfdG9fMzlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBCbGFja19NYWxlXzE1X3RvXzE5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgQmxhY2tfTWFsZV8yMF90b18zOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIE90aGVyX01hbGVfMTVfdG9fMTlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBPdGhlcl9NYWxlXzIwX3RvXzM5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgVW5lbXBsb3ltZW50X3JhdGUgKwogICAgICAgICAgICAgICAgICAgICAgICBQb3ZlcnR5X3JhdGUgKyAKICAgICAgICAgICAgICAgICAgICAgICAgUG9wdWxhdGlvbl9sb2cgKyAKICAgICAgICAgICAgICAgICAgICAgICAgcG9saWNlX3Blcl8xMDBrX2xhZywKICAgICAgICAgICAgICAgICAgICAgICBlZmZlY3QgPSAidHdvd2F5cyIsCiAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSAid2l0aGluIiwKICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRfcGFuZWxfRE9OT0hVRSkKCnBodGVzdChET05PSFVFX3dpdGhpbl9tb2RlbCwgRE9OT0hVRV9yYW5kb21fbW9kZWwpCgpgYGAKClRoaXMgdGVzdCBldmFsdWF0ZXMgaWYgdGhlcmUgYXJlIGVycm9ycyAkdV9pJCB0aGF0IGFyZSBjb3JyZWxhdGVkIHdpdGggYW55IG9mIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMuIAoKV2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMsIHRoYXQgdGhlcmUgYXJlIG5vIGluY29uc2lzdGVuY2llcywgYW5kIGFyZSBjb25maXJtZWQgaW4gb3VyIHBsYW4gdG8gdXNlZCBhIGZpeGVkIGVmZmVjdHMgbW9kZWwuCgoKCkZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHRoZXNlIHRlc3RzIGFuZCB0aGlzIHBhY2thZ2UsIHNlZSBbaGVyZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3BsbS92aWduZXR0ZXMvcGxtUGFja2FnZS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICBhbmQgW2hlcmVdKGh0dHA6Ly93d3cucHJpbmNldG9uLmVkdS9+b3RvcnJlcy9QYW5lbDEwMVIucGRmKXt0YXJnZXQ9Il9ibGFuayJ9LgoKYXZvY2Fkby0gIHdoYXQgZG8geW91IHRoaW5rIGFib3V0IHJlZmVyZW5jaW5nIHRoZXNlIHNsaWRlcyBmcm9tIFByaW5jZXRvbj8KCgpBIGZpbmFsIG5vdGUgYWJvdXQgdGhlIGZpeGVkIGFuZCByYW5kb20gZWZmZWN0cyB0ZXJtaW5vbG9neSBhbmQgaG93IHRoaXMgaXMgc2xpZ2h0bHkgZGlmZmVyZW50IHRoYW4gb3RoZXIgZGVmaW5pdGlvbnM6CgpBY2NvcmRpbmcgdG8gdGhlIGRvY3VtZW50YXRpb24gZm9yIHRoZSBbUExNIHBhY2thZ2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9wbG0vdmlnbmV0dGVzL3BsbVBhY2thZ2UuaHRtbCk6Cj5UaGUgZml4ZWQvcmFuZG9tIGVmZmVjdHMgdGVybWlub2xvZ3kgaW4gZWNvbm9tZXRyaWNzIGlzIG9mdGVuIHJlY29nbml6ZWQgdG8gYmUgbWlzbGVhZGluZywgYXMgYm90aCBhcmUgdHJlYXRlZCBhcyByYW5kb20gdmFyaWF0ZXMgaW4gbW9kZXJuIGVjb25vbWV0cmljcyAoc2VlLCBlLmcuLCBXb29sZHJpZGdlICgyMDAyKSAxMC4yLjEpLiBJdCBoYXMgYmVlbiByZWNvZ25pemVkIHNpbmNlIE11bmRsYWvigJlzIGNsYXNzaWMgcGFwZXIgKE11bmRsYWsgKDE5NzgpKSB0aGF0IHRoZSBmdW5kYW1lbnRhbCBpc3N1ZSBpcyB3aGV0aGVyIHRoZSB1bm9ic2VydmVkIGVmZmVjdHMgYXJlIGNvcnJlbGF0ZWQgd2l0aCB0aGUgcmVncmVzc29ycyBvciBub3QuIEluIHRoaXMgbGFzdCBjYXNlLCB0aGV5IGNhbiBzYWZlbHkgYmUgbGVmdCBpbiB0aGUgZXJyb3IgdGVybSwgYW5kIHRoZSBzZXJpYWwgY29ycmVsYXRpb24gdGhleSBpbmR1Y2UgaXMgY2FyZWQgZm9yIGJ5IG1lYW5zIG9mIGFwcHJvcHJpYXRlIEdMUyB0cmFuc2Zvcm1hdGlvbnMuIE9uIHRoZSBjb250cmFyeSwgaW4gdGhlIGNhc2Ugb2YgY29ycmVsYXRpb24sIOKAnGZpeGVkIGVmZmVjdHPigJ0gbWV0aG9kcyBzdWNoIGFzIGxlYXN0IHNxdWFyZXMgZHVtbXkgdmFyaWFibGVzIG9yIHRpbWUtZGVtZWFuaW5nIGFyZSBuZWVkZWQsIHdoaWNoIGV4cGxpY2l0bHksIGFsdGhvdWdoIGluY29uc2lzdGVudGx5MjcsIGVzdGltYXRlIGEgZ3JvdXDigJMgKG9yIHRpbWXigJMpIGludmFyaWFudCBhZGRpdGlvbmFsIHBhcmFtZXRlciBmb3IgZWFjaCBncm91cCAob3IgdGltZSBwZXJpb2QpLgoKPlRodXMsIGZyb20gdGhlIHBvaW50IG9mIHZpZXcgb2YgbW9kZWwgc3BlY2lmaWNhdGlvbiwgaGF2aW5nIGZpeGVkIGVmZmVjdHMgaW4gYW4gZWNvbm9tZXRyaWMgbW9kZWwgaGFzIHRoZSBtZWFuaW5nIG9mIGFsbG93aW5nIHRoZSBpbnRlcmNlcHQgdG8gdmFyeSB3aXRoIGdyb3VwLCBvciB0aW1lLCBvciBib3RoLCB3aGlsZSB0aGUgb3RoZXIgcGFyYW1ldGVycyBhcmUgZ2VuZXJhbGx5IHN0aWxsIGFzc3VtZWQgdG8gYmUgaG9tb2dlbmVvdXMuIEhhdmluZyByYW5kb20gZWZmZWN0cyBtZWFucyBoYXZpbmcgYSBncm91cOKAkyAob3IgdGltZeKAkywgb3IgYm90aCkgc3BlY2lmaWMgY29tcG9uZW50IGluIHRoZSBlcnJvciB0ZXJtLgoKPkluIHRoZSBtaXhlZCBtb2RlbHMgbGl0ZXJhdHVyZSwgb24gdGhlIGNvbnRyYXJ5LCBmaXhlZCBlZmZlY3QgaW5kaWNhdGVzIGEgcGFyYW1ldGVyIHRoYXQgaXMgYXNzdW1lZCBjb25zdGFudCwgd2hpbGUgcmFuZG9tIGVmZmVjdHMgYXJlIHBhcmFtZXRlcnMgdGhhdCB2YXJ5IHJhbmRvbWx5IGFyb3VuZCB6ZXJvIGFjY29yZGluZyB0byBhIGpvaW50IG11bHRpdmFyaWF0ZSBub3JtYWwgZGlzdHJpYnV0aW9uLgoKCiMjIE11c3RhcmQgYW5kIExvdHQKCk9rLCBub3cgd2Ugd2lsbCBkbyB0aGUgc2FtZSBmb3IgdGhlIE11c3RhcmQgYW5kIExvdHQgYW5hbHlzaXMuIEluIHRoaXMgY2FzZSB3ZSB3b3VsZCBoYXZlIGEgdmVyeSBsYXJnZSBmb3JtdWxhIHRvIHdyaXRlLiBTbyBpbnN0ZWFkLCB3ZSBjYW4gdXNlIHRoZSBgYXMuZm9ybXVsYSgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0YXRzYCBwYWNrYWdlIGFuZCB0aGUgYmFzZSBgcGFzdGUoKWAgZnVuY3Rpb24gdG8gY29tYmluZSBhbGwgb2Ygb3VyIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBpbnRvIG9uZSBmb3JtdWxhIHdpdGhvdXQgbWFraW5nIGEgbWlzdGFrZS4gRmlyc3Qgd2Ugd2lsbCBjcmVhdGUgYW4gb2JqZWN0IHdoZXJlIHdlIHNlbGVjdCBvbmx5IGZvciB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzLiAKCmF2b2NhZG8gSSB0cmllZCB1c2luZyBnbHVlIG9yIGRwbHlyOjpjb2xsYXBzZSB0byBtYWtlIHRoaXMgdGlkeXZlcnNlIGJ1dCB0aGlzIGRpZG4ndCB3b3JrCgpgYGB7cn0KTE9UVF92YXJpYWJsZXMgPC0gTE9UVF9ERiAlPiUKICBkcGx5cjo6c2VsZWN0KFJUQ19MQVcsCiAgICAgICAgICAgICAgICBjb250YWlucyhjKCJXaGl0ZSIsIkJsYWNrIiwiT3RoZXIiKSksCiAgICAgICAgICAgICAgICBVbmVtcGxveW1lbnRfcmF0ZSwKICAgICAgICAgICAgICAgIFBvdmVydHlfcmF0ZSwKICAgICAgICAgICAgICAgIFBvcHVsYXRpb25fbG9nLAogICAgICAgICAgICAgICAgcG9saWNlX3Blcl8xMDBrX2xhZykgJT4lCiAgY29sbmFtZXMoKQoKCkxPVFRfZm1sYSA8LSBhcy5mb3JtdWxhKHBhc3RlKCJWaW9sX2NyaW1lX3JhdGVfMWtfbG9nIH4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShMT1RUX3ZhcmlhYmxlcywgY29sbGFwc2UgPSAiICsgIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICApCgpMT1RUX2ZtbGEKCmBgYAoKVGhhdCBpcyBxdWl0ZSB0aGUgZm9ybXVsYSEKCk9LLCBub3cgYWdhaW4gd2Ugd2lsbCBtYWtlIGEgcGFuZWwgZGF0YSBmcmFtZSBhbmQgd2Ugd2lsbCBwZXJmb3JtIGZpdCBhIGZpeGVkIGVmZmVjdCB0d28td2F5IG1vZGVsIGZvciB0aW1lIGFuZCBpbmRpdmlkdWFscyAoYFNUQVRFYCkgd2l0aCB0aGlzIGRhdGEgYXMgd2VsbC4KCmBgYHtyfQoKZF9wYW5lbF9MT1RUIDwtIHBkYXRhLmZyYW1lKExPVFRfREYsIGluZGV4PWMoIlNUQVRFIiwgIllFQVIiKSkKCkxPVFRfT1VUUFVUIDwtIHBsbShMT1RUX2ZtbGEsCiAgICAgICAgICAgICAgICAgICAgICBtb2RlbCA9ICJ3aXRoaW4iLAogICAgICAgICAgICAgICAgICAgICBlZmZlY3QgPSAidHdvd2F5cyIsCiAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRfcGFuZWxfTE9UVCkKCnN1bW1hcnkoTE9UVF9PVVRQVVQpCgpMT1RUX09VVFBVVF9USURZIDwtIHRpZHkoTE9UVF9PVVRQVVQsIGNvbmYuaW50ID0gMC45NSkKCkxPVFRfT1VUUFVUX1RJRFkkQW5hbHlzaXMgPC0gIkFuYWx5c2lzIDIiCmBgYAoKCiMjIFJUQyBjb2VmZmljaWVudCBjb21wYXJpc29uCgpOb3cgbGV0J3MgbWFrZSBhIHBsb3QgdG8gY29tcGFyZSB0aGUgY29lZmZpY2llbnQgZXN0aW1hdGUgZm9yIHRoZSBSaWdodC10by1jYXJyeSBsYXcgYWRvcHRpb24gdmFyaWFibGUgaW4gZWFjaCBtb2RlbC4KCkZpcnN0IHdlIHdpbGwgY29tYmluZSBtb2RlbCBmaXQgaW5mb3JtYXRpb24gZm9yIHRoaXMgY29lZmZpY2llbnQgZm9yIGVhY2ggbW9kZWwuCgpgYGB7cn0KY29tcGFyaW5nX2FuYWx5c2VzIDwtIERPTk9IVUVfT1VUUFVUX1RJRFkgJT4lCiAgYmluZF9yb3dzKExPVFRfT1VUUFVUX1RJRFkpICU+JQogIGZpbHRlcih0ZXJtID09ICJSVENfTEFXVFJVRSIpCgpjb21wYXJpbmdfYW5hbHlzZXMKYGBgCgpXZSBjYW4gc2VlIHRoYXQgZm9yIHRoZSBmaXJzdCBhbmFseXNpcyAoc2ltaWxhciB0byB0aGUgW0Rvbm9odWUgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZikge3RhcmdldD0iX2JsYW5rIn0gc3R1ZHkpIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZSBmb3IgdGhlIHByZXNlbmNlIG9mIGEgcGVybWlzc2l2ZSBSaWdodC10by1jYXJyeSBsYXcgaXMgcG9zaXRpdmUsIHdoaWxlIGZvciB0aGUgc2Vjb25kIGFuYWx5c2lzIChzaW1pbGFyIHRvIHRoZSBbTXVzdGFyZCBhbmQgTG90dF0oaHR0cHM6Ly9jaGljYWdvdW5ib3VuZC51Y2hpY2Fnby5lZHUvY2dpL3ZpZXdjb250ZW50LmNnaT9hcnRpY2xlPTExNTAmY29udGV4dD1sYXdfYW5kX2Vjb25vbWljcyl7dGFyZ2V0PSJfYmxhbmsifSBzdHVkeSkgdGhlIGNvZWZmaWNpZW50IGVzdGltYXRlIGlzIG5lZ2F0aXZlLiBUaHVzIGluIHRoZSBmaXJzdCBhbmFseXNpcyB3ZSBjb3VsZCBjb25jbHVkZSB0aGF0IHRoZSBlZmZlY3Qgb2YgYWRvcHRpbmcgcGVybWlzc2l2ZSByaWdodC10by1jYXJyeSBsYXdzICBtYXkgYmUgYXNzb2NpYXRlZCB3aXRoIGluY3JlYXNlcyBpbiB2aW9sZW50IGNyaW1lIChhbHRob3VnaCB0aGlzIHdhcyBub3QgYSBzaWduaWZpY2FudCByZXN1bHQgKGluIGNvbnRyYXN0IHdpdGggdGhlIHJlYWwgW0Rvbm9odWUgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZikge3RhcmdldD0iX2JsYW5rIn0gc3R1ZHkgKSk7IHdoaWxlIGluIHRoZSBvdGhlciBhbmFseXNpcyB3ZSBjb3VsZCBjb25jbHVkZSB0aGF0IHRoZSBsYXdzIG1heSBiZSBhc3NvY2lhdGVkIHdpdGggZGVjcmVhc2VzIGluIHZpb2xlbnQgY3JpbWUuCgpMZXQncyBtYWtlIGEgcGxvdCBvZiB0aGlzIGZpbmRpbmcuIFdlIHdpbGwgc2hvdyBlcnJvciBiYXJzIGZvciB0aGUgY29lZmZpY2llbnQgZXN0aW1hdGVzIGZvciBib3RoIGFuYWx5c2VzIHVzaW5nIHRoZSBgZ2VvbV9lcnJvcmJhcigpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UuIFRoaXMgcmVxdWlyZXMgc3BlY2lmeWluZyB0aGUgbWluaW11bSBhbmQgbWF4aW11bSBmb3Igb3VyIGVycm9yIGJhciwgd2hpY2ggaW4gb3VyIGNhc2Ugd2Ugd291bGQgbGlrZSB0byBiZSB0aGUgbG93IGFuZCBoaWdoIHZhbHVlcyBvZiBvdXIgY29uZmlkZW5jZSBpbnRlcnZhbHMgZm9yIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMuIFdlIHdpbGwgYWxzbyBhZGQgYSBob3Jpem9udGFsIGxpbmUgYXQgeSA9IDAgdXNpbmcgdGhlIGBnZW9tX2hsaW5lKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4gCgpGaW5hbGx5IHdlIHdpbGwgYWRkIGFycm93cyB0byBlbXBoYXNpemUgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIGRpcmVjdGlvbiBvZiB0aGUgZmluZGluZ3MgdXNpbmcgdGhlIGBnZW9tX3NlZ21lbnQoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlLiBVc2luZyB0aGUgYGFycm93KClgIGZ1bmN0aW9uLCB3ZSBjYW4gc3BlY2lmeSBkZXRhaWxzIGFib3V0IHRoZSBhcnJvdyB3ZSB3b3VsZCBsaWtlIHRvIGFkZC4KCmBgYHtyfQpjb21wYXJpbmdfYW5hbHlzZXNfcGxvdCA8LSBnZ3Bsb3QoY29tcGFyaW5nX2FuYWx5c2VzKSArIAogIGdlb21fcG9pbnQoYWVzKHggPSBBbmFseXNpcywgeSA9IGVzdGltYXRlKSkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHggPSBBbmFseXNpcywgeW1pbiA9IGNvbmYubG93LCB5bWF4ID0gY29uZi5oaWdoKSwgd2lkdGggPSAwLjI1KSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZCIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKC0wLjIsIDAuMiwgYnkgPSAwLjA1KSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKC0wLjIsIDAuMiwgYnkgPSAwLjA1KSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtMC4yLDAuMikpICsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSAxLCB5ID0gMC4xMjUsIHhlbmQgPSAxLCB5ZW5kID0gMC4xNzUpLAogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGFuZ2xlID0gNDUsIGVuZHMgPSAibGFzdCIsIHR5cGUgPSAib3BlbiIpLAogICAgICAgICAgICAgICBzaXplID0gMiwKICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JlZW4iLAogICAgICAgICAgICAgICBsaW5lZW5kID0gImJ1dHQiLAogICAgICAgICAgICAgICBsaW5lam9pbiA9ICJtaXRyZSIpICsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSAyLCB5ID0gLTAuMTI1LCB4ZW5kID0gMiwgeWVuZCA9IC0wLjE3NSksCiAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3coYW5nbGUgPSA0NSwgZW5kcyA9ICJsYXN0IiwgdHlwZSA9ICJvcGVuIiksCiAgICAgICAgICAgICAgIHNpemUgPSAyLAogICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLAogICAgICAgICAgICAgICBsaW5lZW5kID0gImJ1dHQiLAogICAgICAgICAgICAgICBsaW5lam9pbiA9ICJtaXRyZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LCBjb2xvciA9ICJibGFjayIpKSArCiAgbGFicyh0aXRsZSA9ICJFZmZlY3QgZXN0aW1hdGUgb24gbG4odmlvbGVudCBjcmltZXMgcGVyIDEwMCwwMDAgcGVvcGxlKSIsCiAgICAgICB5ID0gIiAgRWZmZWN0IGVzdGltYXRlICg5NSUgQ0kpIikKCmNvbXBhcmluZ19hbmFseXNlc19wbG90CmBgYAoKV2UgY2FuIHNlZSB0aGF0IG1vc3Qgb2YgdGhlIHBvc3NpYmxlIHJhbmdlIG9mIHZhbHVlcyBmb3IgdGhlIGVzdGltYXRlIGluIGFuYWx5c2lzIDEgYXJlIHBvc2l0aXZlLCB3aGlsZSB0aGV5IGFyZSBhbGwgbmVnYXRpdmUgZm9yIGFuYWx5c2lzIDIuCgojICoqTXVsdGljb2xsaW5lYXJpdHkgYW5hbHlzaXMqKgoqKioKCkhvdyBkaWQgdGhlIGFib3ZlIGhhcHBlbj8KClRoZSBhbmFseXNpcyBkYXRhIGZyYW1lcyBhcmUgdmVyeSBzaW1pbGFyIHlldCByZW5kZXJlZCB2ZXJ5IGRpZmZlcmVudCByZXN1bHRzLiAKClJlY2FsbCB0aGF0IHRoZSBvbmx5IGRpZmZlcmVuY2UgaXMgdGhlIG51bWJlciBvZiBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMuIFRoZSBudW1iZXIgb2Ygcm93cyBvciBvYnNlcnZhdGlvbnMgaXMgdGhlIHNhbWUuIFdlIGNhbiB1c2UgdGhlIGBhbGxfZXF1YWwoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBjb21wYXJlIHRoZSBudW1iZXIgb2YgY29sdW1ucyBvZiBvdXIgRG9ub2h1ZS1saWtlIGRhdGEgYW5kIG91ciBNdXN0YXJkIGFuZCBMb3R0LWxpa2UgZGF0YS4KCmBgYHtyfQphbGxfZXF1YWwodGFyZ2V0ID0gRE9OT0hVRV9ERiwKICAgICAgICAgIGN1cnJlbnQgPSBMT1RUX0RGLAogICAgICAgICAgaWdub3JlX2NvbF9vcmRlciA9IFRSVUUsCiAgICAgICAgICBpZ25vcmVfcm93X29yZGVyID0gVFJVRSkKYGBgCgpVc2luZyB0aGUgYmFzZSBgZGltKClgIGZ1bmN0aW9uIHdlIGNhbiBhbHNvIGxvb2sgYXQgdGhlIG51bWJlciBvZiByb3dzIGZvciBlYWNoIGFuZCBzZWUgdGhhdCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpcyB0aGUgc2FtZSBmb3IgYm90aCBkYXRhc2V0cy4KCmBgYHtyfQpkaW0oRE9OT0hVRV9ERilbMV0KZGltKExPVFRfREYpWzFdCmBgYAoKVGhlIG9ubHkgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gZGF0YSBmcmFtZXMgcmVzdHMgaW4gaG93IHRoZSBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMgd2VyZSBwYXJhbWV0ZXJpemVkLgoKYGBge3J9CkRPTk9IVUVfREYgJT4lCiAgZHBseXI6OnNlbGVjdChjb250YWlucygieWVhcnMiKSkgJT4lCiAgY29sbmFtZXMoKQoKTE9UVF9ERiAlPiUKICBkcGx5cjo6c2VsZWN0KGNvbnRhaW5zKCJ5ZWFycyIpKSAlPiUKICBjb2xuYW1lcygpCmBgYAoKQ2xlYXJseSwgdGhpcyBoYWQgYW4gZWZmZWN0IG9uIHRoZSByZXN1bHRzIG9mIHRoZSBhbmFseXNpcy4gCgpMZXQncyBleHBsb3JlIGhvdyB0aGlzIG9jY3VycmVkLiAKCldoZW4gc2VlbWluZ2x5IGluZGVwZW5kZW50IHZhcmlhYmxlcyBhcmUgaGlnaGx5IHJlbGF0ZWQgdG8gb25lIGFub3RoZXIsIHRoZSByZWxhdGlvbnNoaXBzIGVzdGltYXRlZCBpbiBhbiBhbmFseXNpcyBtYXkgYmUgZGlzdG9ydGVkLiAKCkluIHJlZ3Jlc3Npb24gYW5hbHlzaXMsIHRoaXMgZGlzdG9ydGlvbiBpcyBvZnRlbiBhIGJ5LXByb2R1Y3Qgb2YgYSB2aW9sYXRpb24gb2YgdGhlIGluZGVwZW5kZW5jZSBhc3N1bXB0aW9uLiBUaGlzIGRpc3RvcnRpb24sIGlmIGxhcmdlIGVub3VnaCwgY2FuIGltcGFjdCBzdGF0aXN0aWNhbCBpbmZlcmVuY2UuIAoKVGhlIHBoZW5vbWVuYSBjYWxsZWQgbXVsdGljb2xsaW5lYXJpdHkgb2NjdXJzIHdoZW4gaW5kZXBlbmRlbnQgdmFyaWFibGVzIGFyZSBoaWdobHkgcmVsYXRlZCB0byBvbmUgYW5vdGhlcgoKVGhlcmUgYXJlIHNldmVyYWwgd2F5cyB3ZSBjYW4gZGlhZ25vc2UgbXVsdGljb2xsaW5lYXJpdHkuCgojIyMgQ29ycmVsYXRpb24KCk9uZSB3YXkgd2UgY2FuIGV2YWx1YXRlIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdmFyaWFibGVzIGlzIGJ5IGV4YW1pbmluZyB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB2YXJpYWJsZSBwYWlycy4KCjxzdHlsZT4KZGl2LmJsdWUgeyBiYWNrZ3JvdW5kLWNvbG9yOiNlNmYwZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMjBweDt9Cjwvc3R5bGU+CjxkaXYgY2xhc3MgPSAiYmx1ZSI+CgpJdCBpcyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IG11bHRpY29sbGluZWFyaXR5IGFuZCBjb3JyZWxhdGlvbiBhcmUgbm90IG9uZSBhbmQgdGhlIHNhbWUuIFtDb3JyZWxhdGlvbl0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNTA3OTA5My8pIGNhbiBiZSB0aG91Z2h0IG9mIGFzIHRoZSBzdHJlbmd0aCBvZiBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXJpYWJsZXMuIE9uIHRoZSBvdGhlciBoYW5kLCBjb2xsaW5lYXJpdHkgY2FuIGJlIHRob3VnaHQgb2YgYXMgdHdvIGluZGVwZW5kZW50IHZhcmlhYmxlcyBoYXZpbmcgYSBsaW5lYXIgcmVsYXRpb25zaGlwIG9yIGFzc29jaWF0aW9uLiBNdWx0aWNvbGxpbmVhcml0eSBjYW4gYmUgdGhvdWdodCBvZiBhcyBjb2xsaW5lYXJpdHkgYW1vbmcgbXVsdGlwbGUgKDMrKSByZWdyZXNzb3JzIChpbmRlcGVuZGVudCB2YXJpYWJsZXMpIGluIGEgcmVncmVzc2lvbiBhbmFseXNpcywgd2hpY2ggY2FuIG9jY3VyIHdoZW4gcmVncmVzc29ycyBhcmUgaGlnaGx5IGNvcnJlbGF0ZWQuCgo8L2Rpdj4KCgpBY2NvcmRpbmcgdG8gW1dpa2lwZWRpYV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTXVsdGljb2xsaW5lYXJpdHkpe3RhcmdldD0iX2JsYW5rIn06Cgo+IG11bHRpY29sbGluZWFyaXR5IChhbHNvIGNvbGxpbmVhcml0eSkgaXMgYSBwaGVub21lbm9uIGluIHdoaWNoIG9uZSBwcmVkaWN0b3IgdmFyaWFibGUgaW4gYSBtdWx0aXBsZSByZWdyZXNzaW9uIG1vZGVsIGNhbiBiZSBsaW5lYXJseSBwcmVkaWN0ZWQgZnJvbSB0aGUgb3RoZXJzIHdpdGggYSBzdWJzdGFudGlhbCBkZWdyZWUgb2YgYWNjdXJhY3kuIAoKVGh1cyBjb2xsaW5lYXJpdHkgZGVzY3JpYmVzIGxpbmVhciBwcmVkaWN0aW9uIG9yIGFzc29jaWF0aW9uLiBPZnRlbiB0aG9zZSB2YXJpYWJsZXMgd2lsbCBiZSBoaWdobHkgY29ycmVsYXRlZC4KClRoZSBpc3N1ZSB3aXRoIHRoaXMgaW4gbGluZWFyIHJlZ3Jlc3Npb24sIGlzIHRoYXQgbGluZWFyIHJlZ3Jlc3Npb24gYWltcyB0byBkZXRlcm1pbmUgaG93IGEgb25lIHVuaXQgY2hhbmdlIGluIGEgcmVncmVzc29yIGluZmx1ZW5jZXMgYSBvbmUgdW5pdCBjaGFuZ2UgaW4gdGhlIGRlcGVuZGVudCB2YXJpYWJsZS4gSW4gZmFjdCwgdGhpcyBpcyB3aGF0IHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMgYWltIHRvIHRlbGwgdXMgZm9yIGVhY2ggcmVncmVzc29yLgoKSG93ZXZlciwgaWYgb3VyIHJlZ3Jlc3NvcnMgYXJlIGFsc28gbGluZWFybHkgcmVsYXRlZCwgdGhhbiBpdCBiZWNvbWVzIGRpZmZpY3VsdCB0byBkZXRlcm1pbmUgdGhlIGVmZmVjdCBvZiBlYWNoIHJlZ3Jlc3NvciBvbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGFuZCBtdWx0aWNvbGxpbmVhcml0eSBjYW4gY2F1c2UgaW5zdGFiaWxpdHkgaW4gdGhlIGVzdGltYXRpb24gb2YgW2NvZWZmaWNpZW50IGVzdGltYXRlc10oaHR0cHM6Ly9zdGF0aXN0aWNzYnlqaW0uY29tL2dsb3NzYXJ5L3JlZ3Jlc3Npb24tY29lZmZpY2llbnQvKXt0YXJnZXQ9Il9ibGFuayJ9LCBtYWtpbmcgdGhlbSB1bnJlbGlhYmxlLiBDb2VmZmljaWVudHMgbWF5IGJlIGluZmxhdGVkLCBkZWZsYXRlZCwgb3IgdGhlaXIgc2lnbnMgbWF5IGNoYW5nZS4KCmF2b2NhZG8uLi4gd2hhdCBpZiB0aGUgcmVncmVzc29ycyBoYXZlIGEgbm9ubGluZWFyIHJlbGF0aW9uc2hpcD8/CgoKYXZvY2FkbzogSSByZWFsbHkgbGlrZWQgdGhlc2UgZXhwbGFuYXRpb25zIC0gbm90IHN1cmUgaWYgd2Ugd2FudCB0byBpbmNsdWRlIHRoZXNlIGFzIHJlc291cmNlczoKaHR0cHM6Ly9ibG9nLmNsYWlydm95YW50c29mdC5jb20vY29ycmVsYXRpb24tYW5kLWNvbGxpbmVhcml0eS1ob3ctdGhleS1jYW4tbWFrZS1vci1icmVhay1hLW1vZGVsLTkxMzVmYmU2OTM2YQoKaHR0cHM6Ly9tZWRpdW0uY29tL3N3bGgvbXVsdGljb2xsaW5lYXJpdHktYW5kLXZhcmlhbmNlLWluZmxhdGlvbi1mYWN0b3ItYmM3NGFmMzZiMWM5CgojIyMjIFNjYXR0ZXIgcGxvdHMKCk9uZSBvZiB0aGUgd2F5cyB0byBkaWFnbm9zZSBtdWx0aWNvbGxpbmVhcml0eSBpbiBhIHJlZ3Jlc3Npb24gbW9kZWwgaXMgdG8gZmlyc3Qgc2VlIGlmIHRoZXJlIGFyZSByZWdyZXNzb3JzIHRoYXQgYXJlIGhpZ2hseSBjb3JyZWxhdGVkLiBJZiBzbywgdGhpcyBzdWdnZXN0cyB0aGF0IHdlIHNob3VsZCBpbnZlc3RpZ2F0ZSBmdXJ0aGVyIHRvIHNlZSBpZiB0aGVzZSB2YXJpYWJsZXMgYXJlIGluIGZhY3QgbGluZWFybHkgcHJlZGljdGluZyBvbmUgYW5vdGhlci4KCk9uZSB3YXkgdG8gbG9vayBhdCBjb3JyZWxhdGlvbiBhY3Jvc3MgcGFpcnMgb2YgdmFyaWFibGVzIGlzIHRvIHVzZSB0aGUgYGdncGFpcnMoKWAgZnVuY3Rpb24gb2YgdGhlIGBHR2FsbHlgIHBhY2thZ2UuCgpgYGB7cn0KY29sbmFtZXMoRE9OT0hVRV9ERikKCkRPTk9IVUVfREYgJT4lIAogIGRwbHlyOjpzZWxlY3QoUlRDX0xBVywKICAgICAgICAgICAgICAgIFZpb2xfY3JpbWVfcmF0ZV8xa19sb2csCiAgICAgICAgICAgICAgICBVbmVtcGxveW1lbnRfcmF0ZSwKICAgICAgICAgICAgICAgIFBvdmVydHlfcmF0ZSwKICAgICAgICAgICAgICAgIFBvcHVsYXRpb25fbG9nKSAlPiUgCiAgZ2dwYWlycyguLAogICAgICAgICAgY29sdW1ucyA9IGMoMjo1KSwKICAgICAgICAgIGxvd2VyID0gbGlzdChjb250aW51b3VzID0gd3JhcCgic21vb3RoX2xvZXNzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjEpKSkKYGBgCldlIGNhbiBzZWUgdGhhdCBmb3IgdGhlIG5vbi1kZW1vZ3JhcGhpYyB2YXJpYWJsZXMsIHRoZXJlIGlzIHZlcnkgbGl0dGxlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHBhaXJzIG9mIHZhcmlhYmxlcy4gT25seSB0aGUgdW5lbXBsb3ltZW50IHJhdGUgYW5kIHRoZSBwb3ZlcnR5IHJhdGUgc2hvdyByZWxhdGl2ZWx5IHN0cm9uZyBjb3JyZWxhdGlvbiwgYXMgb25lIG1pZ2h0IGV4cGVjdC4gCgoKIyMjIyBIZWF0bWFwcwoKQW5vdGhlciB3YXkgdG8gbG9vayBhdCBjb3JyZWxhdGlvbiBpZiB3ZSBoYXZlIG1hbnkgdmFyaWFibGVzIGlzIHRvIHVzZSBoZWF0bWFwcy4KCkxldCdzIHRvIHRoaXMgbm93IGZvciB0aGUgZGVtb2dyYXBoaWMgdmFyaWFibGVzIGZvciBlYWNoIGFuYWx5c2lzLgoKVGhlIGBnZ2NvcnJwbG90KClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwY29ycGxvdGAgcGFja2FnZSBpcyBvbmUgd2F5IHRvIGNyZWF0ZSBzdWNoIGEgaGVhdG1hcC4KClRoaXMgcmVxdWlyZXMgZmlyc3QgY2FsY3VsYXRpbmcgdGhlIGNvcnJlbGF0aW9uIHZhbHVlcyB1c2luZyB0aGUgYGNvcigpYCBmdW5jdGlvbiBvZiB0aGUgYHN0YXRzYCBwYWNrYWdlLgoKV2Ugd2lsbCBhZGQgYSBsZWdlbmQgdGl0bGUgdG8gaW5jbHVkZSAkXHJobyQgYnkgdXNpbmcgdGhlIGJhc2UgYGV4cHJlc3Npb24oKWAgZnVuY3Rpb24sIHdoaWNoIHdpbGwgY29udmVydCB0aGUgd3JpdHRlbiBmb3Igb2YgYCJyaG8iYCB0byB0aGUgR3JlZWsgc3ltYm9sLgoKYGBge3J9CmNvcl9ET05PSFVFX2RlbSA8LSBjb3IoRE9OT0hVRV9ERiAlPiUgZHBseXI6OnNlbGVjdChjb250YWlucygiX3llYXJzIikpKQoKY29ycl9tYXRfRE9OT0hVRSA8LSBnZ2NvcnJwbG90KGNvcl9ET05PSFVFX2RlbSwKICAgICAgICAgICB0bC5jZXggPSA2LAogICAgICAgICAgIGhjLm9yZGVyID0gVFJVRSwKICAgICAgICAgICBjb2xvcnMgPSBjKCJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgIndoaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICJyZWQiKSwKICAgICAgICAgICBvdXRsaW5lLmNvbG9yID0gInRyYW5zcGFyZW50IiwKICAgICAgICAgICB0aXRsZSA9ICJDb3JyZWxhdGlvbiBNYXRyaXgsIEFuYWx5c2lzIDEiLAogICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGV4cHJlc3Npb24ocmhvKSkKCgpjb3JyX21hdF9ET05PSFVFCgpjb3JfTE9UVF9kZW0gPC0gY29yKExPVFRfREYgJT4lIGRwbHlyOjpzZWxlY3QoY29udGFpbnMoIl95ZWFycyIpKSkKCmNvcnJfbWF0X0xPVFQgPC0gZ2djb3JycGxvdChjb3JfTE9UVF9kZW0sCiAgICAgICAgICAgdGwuY2V4ID0gNiwKICAgICAgICAgICBoYy5vcmRlciA9IFRSVUUsCiAgICAgICAgICAgY29sb3JzID0gYygicmVkIiwKICAgICAgICAgICAgICAgICAgICAgICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAicmVkIiksCiAgICAgICAgICAgb3V0bGluZS5jb2xvciA9ICJ0cmFuc3BhcmVudCIsCiAgICAgICAgICAgdGl0bGUgPSAiQ29ycmVsYXRpb24gTWF0cml4LCBBbmFseXNpcyAyIiwKICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBleHByZXNzaW9uKHJobykpCgpjb3JyX21hdF9MT1RUCmBgYApXZSBjYW4gc2VlIHRoYXQgbWFueSBvZiB0aGUgZGVtb2dyYXBoaWMgdmFyaWFibGVzIGFyZSBoaWdobHkgY29ycmVsYXRlZCB3aXRoIG9uZSBhbm90aGVyLiAKCgpUaGUgcHJlc2VuY2Ugb2YgY29ycmVsYXRpb24gYmV0d2VlbiB2YXJpYWJsZXMgc3VnZ2VzdHMgdGhhdCB3ZSBtaWdodCBoYXZlIG11bHRpY29sbGluZWFyaXR5LiBIb3dldmVyIGl0IGRvZXMgbm90IG5lY2Vzc2FyaWx5IG1lYW4gdGhhdCB3ZSBkby4gU28gaG93IGNhbiB3ZSBhc3Nlc3MgdGhpcz8KCgojIyMgQ29lZmZpY2llbnQgZXN0aW1hdGUgaW5zdGFiaWxpdHkKCk9uZSB3YXkgdG8gbG9vayBhdCB0aGUgcG9zc2libGUgaW5mbHVlbmNlIG9mIG11bHRpY29sbGluZWFyaXR5IGlzIHRvIGxvb2sgYXQgdGhlIHN0YWJpbGl0eSBvZiB0aGUgY29lZmZpY2llbnQgZXN0aW1hdGVzLgoKV2Ugd2lsbCBmb2N1cyBvbiB0aGUgYFJUQ19MQVdgIHZhcmlhYmxlIGNvZWZmaWNpZW50IGVzdGltYXRlLCBhcyB0aGlzIGlzIG9mIHBhcnRpY3VsYXIgaW50ZXJlc3QgaW4gb3VyIGNhc2UuCgpUbyBkbyBzbyB3ZSB3aWxsIHBlcmZvcm0gYSBwcm9jZXNzIGNhbGxlZCBbcmVzYW1wbGluZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmVzYW1wbGluZ18oc3RhdGlzdGljcykpe3RhcmdldD0iX2JsYW5rIn0uIFRoaXMgaW52b2x2ZXMgcGVyZm9ybWluZyBtdWx0aXBsZSBpdGVyYXRpb25zIG9mIG91ciBhbmFseXNpcywgYnV0IHdpdGggb25seSBhIHN1YnNldCBvciBzdWItc2FtcGxlIG9mIG91ciBvcmlnaW5hbCBkYXRhLiAgSW4gb3VyIGNhc2Ugd2Ugd2lsbCByZW1vdmUgKipvbmUqKiBvYnNlcnZhdGlvbiBhbmQgc2VlIGlmIHRoYXQgY2hhbmdlcyBvdXIgY29lZmZpY2llbnQgZXN0aW1hdGUgcmVzdWx0cy4gCgoKVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSBzb21lIGZ1bmN0aW9ucyBpbiB0aGUgYHJzYW1wbGVgIHBhY2thZ2Ugd2hpY2ggaXMgdmVyeSB1c2VmdWwgZm9yIHNwbGl0dGluZyBkYXRhIGluIHZhcmlvdXMgd2F5cy4KCldlIHdpbGwgdXNlIHRoZSBgbG9vX2N2KClgIGZ1bmN0aW9uIHdoaWNoIHN0YW5kcyBmb3IgKipsZWF2ZSBvbmUgb3V0KiogW2Nyb3NzIHZhbGlkYXRpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Nyb3NzLXZhbGlkYXRpb25fKHN0YXRpc3RpY3Mpe3RhcmdldD0iX2JsYW5rIn0uIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBzcGxpdCBvdXIgZGF0YSBpbnRvIGV2ZXJ5IHBvc3NpYmxlIHN1YnNldCB3aGVyZSBhIHVuaXF1ZSBvYnNlcnZhdGlvbiBpcyBsZWZ0IG91dCBvZiB0aGUgZGF0YS4KClRoaXMgZnVuY3Rpb24gd2lsbCBob3dldmVyIG9ubHkgcHJlcGFyZSB0aGUgZGF0YSB0byBiZSBzcGxpdC4KClRvIGFjdHVhbGx5IGdldCB0aGUgcmVtYWluaW5nIGRhdGEgYWZ0ZXIgdGhlIHJlbW92YWwgb2YgdGhlIG9ic2VydmF0aW9uIHRoYXQgaXMgbGVmdCBvdXQgd2hlbiBuZWVkIHRvIHVzZSBhIGZ1bmN0aW9uIGNhbGxlZCBgdHJhaW5pbmcoKWAuIFRoaXMgaXMgYmVjYXVzZSB0aGVzZSBmdW5jdGlvbnMgYXJlIG9mdGVuIHVzZWQgZm9yIGluIG1hY2hpbmUgbGVhcm5pbmcgYXBwbGljYXRpb25zIHdoZXJlIHRoZSBkYXRhIGlzIHNwbGl0IGJldHdlZW4gYSBsYXJnZXIgdHJhaW5pbmcgc2V0IGFuZCBhIHNtYWxsZXIgdGVzdGluZyBzZXQuIFRodXMgd2Ugd2FudCB0aGUgbGFyZ2VyICRuLTEkIHN1YnNldCwgYXMgb3Bwb3NlZCB0byB0aGUgc2luZ2xlIHZhbHVlIHRoYXQgaXMgcmVtb3ZlZCwgKHdoaWNoIHdlIGNvdWxkIGdldCB3aXRoIHRoZSBgdGVzdGluZygpYCBmdW5jdGlvbikKCgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIGFuIGV4YW1wbGUgb2YgaG93IHRoaXMgd29ya3MuIDwvc3VtbWFyeT4KCkZpcnN0IHdlIHdpbGwgbWFrZSBhIHRveSBkYXRhc2V0IHRoYXQgaXMgdmVyeSBzaW1wbGUgY2FsbGVkIHRlc3QgdXNpbmcgdGhlIGB0aWJibGUoKWAgZnVuY3Rpb24gb2YgdGhlIGB0aWR5cmAgcGFja2FnZToKYGBge3J9CnRlc3QgPC10aWR5cjo6dGliYmxlKHggPSBjKDEsMiwzKSkKdGVzdApgYGAKCk5vdyB3ZSB3aWxsIHVzZSB0aGUgYGxvb19jdigpYCB0byBjcmVhdGUgbGVhdmUgb25lIG91dCBzcGxpdHM6CmBgYHtyfQp0ZXN0X3NhbXBsZXMgPC0gdGVzdCAlPiUgbG9vX2N2KCkKdGVzdF9zYW1wbGVzCmBgYAoKV2UgY2FuIHRha2UgYSBsb29rIGF0IG9uZSBpbmRpdmlkdWFsIHNwbGl0IHVzaW5nIHRoZSBgcHVsbCgpYCBmdW5jdGlvbjoKCmBgYHtyfQpwdWxsKHRlc3Rfc2FtcGxlcywgc3BsaXRzKQpgYGAKCkhlcmUgeW91IGNhbiBzZWUgdGhhdCAyIHZhbHVlcyBhcmUgaW50ZW5kZWQgZm9yIHRoZSB0cmFpbmluZyBzZXQgKGFsc28gY2FsbGVkIEFuYWx5c2lzIHNldCksIDEgdmFsdWUgaXMgaW50ZW5kZWQgZm9yIHRoZSB0ZXN0aW5nIHNldCAoYWxzbyBjYWxsZWQgQXNzZXNzbWVudCBzZXQpLCBhbmQgMyB2YWx1ZXMgd2VyZSBwcmVzZW50IGluaXRpYWxseS4KCk5vdyB3ZSB3aWxsIHVzZSB0aGUgYHRyYWluaW5nKClgIGZ1bmN0aW9uIHRvIGdldCB0aGUgZGF0YSB3aXRob3V0IHRoZSBvYnNlcnZhdGlvbiB0aGF0IGlzIHNldCBhc2lkZS4gSGVyZSBpcyB0aGUgZGF0YSBmb3IgdGhlIGZpcnN0IHN1YnNldDoKYGBge3J9CnRyYWluaW5nKHB1bGwodGVzdF9zYW1wbGVzLCBzcGxpdHMpW1sxXV0pCmBgYAoKTm93IHdlIHdpbGwgdXNlIHRoZSBgbWFwKClgIGZ1bmN0aW9uIG9mIGBwdXJycmAgdG8gZ2V0IGFsbCBwb3NzaWJsZSBgdHJhaW5pbmdgIHN1YnNldCBvZiB0aGUgZGF0YS4KYGBge3J9Cgp0ZXN0X3N1YnNldHMgPC0gbWFwKHB1bGwodGVzdF9zYW1wbGVzLCBzcGxpdHMpLCB0cmFpbmluZykKdGVzdF9zdWJzZXRzCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSAzIHBvc3NpYmxlIHN1YnNldHMgdGhhdCBsZWF2ZSBvbmUgdmFsdWUgb3V0LiBBbGwgMyBwb3NzaWJsZSBzdWJzZXRzIGFyZSBjcmVhdGVkIHVzaW5nIHRoaXMgbWV0aG9kLiBUaGlzIG1ldGhvZCB3aWxsIGFsd2F5cyBjcmVhdGUgdGhlIHNhbWUgbnVtYmVyIG9mIHN1YnNldHMgYXMgdGhlcmUgYXJlIHVuaXF1ZSB2YWx1ZXMgb3Igcm93cyBpbiB0aGUgZGF0YS4KCjwvZGV0YWlscz4KCgpOb3cgd2Ugd2lsbCB1c2UgdGhpcyBtZXRob2Qgd2l0aCB0aGUgZGF0YSBmcm9tIG91ciBEb25vaHVlLWxpa2UgYW5hbHlzaXMsIHNpbmNlIHRoaXMgZGF0YSBoYXMgYGRpbShkX3BhbmVsX0RPTk9IVUUpWzFdYCByb3dzLCBgZGltKGRfcGFuZWxfRE9OT0hVRSlbMV1gIHN1YnNldHMgd2lsbCBiZSBjcmVhdGVkIHRoYXQgbGVhdmUgb3V0IG9uZSByb3cuCgpGaXJzdCB3ZSB3aWxsIGNyZWF0ZSB0aGUgc3BsaXRzIHVzaW5nIHRoZSBgbG9vX2N2KClgIGZ1bmN0aW9uOgpgYGB7cn0Kc2V0LnNlZWQoMTI0KQpET05PSFVFX3NwbGl0cyA8LSBkX3BhbmVsX0RPTk9IVUUgJT4lIGxvb19jdigpCkRPTk9IVUVfc3BsaXRzCmBgYAoKTm93IHdlIHdpbGwgdXNlIHRoZSBgdHJhaW5pbmcoKWAgZnVuY3Rpb24gdG8gc2VsZWN0IHRoZSByZW1haW5pbmcgZGF0YSB3aXRob3V0IHRoZSB2YWx1ZSB0aGF0IHdhcyByZW1vdmVkIGZvciBlYWNoIHNwbGl0OgoKYGBge3J9CiMgVG8gZ2V0IGFsbCB0aGUgZGF0YSBzdWJzZXRzCkRPTk9IVUVfc3Vic2V0cyA8LW1hcChwdWxsKERPTk9IVUVfc3BsaXRzLCBzcGxpdHMpLCB0cmFpbmluZykKCmdsaW1wc2UoRE9OT0hVRV9zdWJzZXRzW1sxXV0pCmxlbmd0aChET05PSFVFX3N1YnNldHMpCmBgYAoKQXMgZXhwZWN0ZWQgdGhlIGZpcnN0IHN1YnNldCBoYXMgMSwzOTQgcm93cyBhbmQgdGhlcmUgYXJlIDEzOTUgc3Vic2V0cy4KCkxldCdzIHNlZSB3aGF0IG9ic2VydmF0aW9uIHdhcyBsZWZ0IG91dCBpbiB0aGUgZmlyc3Qgc3Vic2V0OgoKYGBge3J9CmRfcGFuZWxfRE9OT0hVRSAlPiUKICBmaWx0ZXIoISByb3duYW1lcyhkX3BhbmVsX0RPTk9IVUUpICAlaW4lIHJvd25hbWVzKERPTk9IVUVfc3Vic2V0c1tbMV1dKSkKCiMgQW5vdGhlciB3YXkgdG8gY2hlY2sgaXMgdG8gdXNlOgpET05PSFVFX3JlbW92ZWQgPC1tYXAocHVsbChET05PSFVFX3NwbGl0cywgc3BsaXRzKSwgdGVzdGluZykKCkRPTk9IVUVfcmVtb3ZlZFtbMV1dCmBgYAoKSXQgbG9va3MgbGlrZSB0aGUgVGV4YXMgZGF0YSBmcm9tIDE5ODggd2FzIHJlbW92ZWQgZnJvbSB0aGUgZmlyc3Qgc3BsaXQuCgoKT0ssIHNvIG5vdyBsZXQncyBmaXQgb3VyIHBhbmVsIHJlZ3Jlc3Npb24gb24gdGhlIGZpcnN0IHN1YnNldCBvZiBkYXRhIGxpa2Ugd2UgZGlkIHByZXZpb3VzbHkuIE5vdGUgdGhhdCB0aGlzIGNhdXNlcyBvdXIgZGF0YSB0byBiZSBhbiB1bmJhbGFuY2VkIHBhbmVsLgpUaGlzIGRvZXMgbm90IHJlcXVpcmUgYW55IGFkanVzdG1lbnQgdG8gdGhlIGNvZGUgdG8gbW9kZWwgdGhlIGRhdGEsIGJ1dCB5b3Ugd2lsbCBub3RpY2UgdGhhdCB0aGUgb3V0cHV0IHdpbGwgbm93IHNheSAidW5iYWxhbmNlZCIuCgpgYGB7cn0KIHN1YnNldF8xX3Jlc3VsdDwtcGxtKFZpb2xfY3JpbWVfcmF0ZV8xa19sb2cgfgogICAgICAgICAgICAgICAgICAgICAgICBSVENfTEFXICsKICAgICAgICAgICAgICAgICAgICAgICAgV2hpdGVfTWFsZV8xNV90b18xOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIFdoaXRlX01hbGVfMjBfdG9fMzlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBCbGFja19NYWxlXzE1X3RvXzE5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgQmxhY2tfTWFsZV8yMF90b18zOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIE90aGVyX01hbGVfMTVfdG9fMTlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBPdGhlcl9NYWxlXzIwX3RvXzM5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgVW5lbXBsb3ltZW50X3JhdGUgKwogICAgICAgICAgICAgICAgICAgICAgICBQb3ZlcnR5X3JhdGUgKyAKICAgICAgICAgICAgICAgICAgICAgICAgUG9wdWxhdGlvbl9sb2cgKyAKICAgICAgICAgICAgICAgICAgICAgICAgcG9saWNlX3Blcl8xMDBrX2xhZywKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IERPTk9IVUVfc3Vic2V0c1tbMV1dLAogICAgICAgICAgICAgICAgICAgICAgIGluZGV4ID0gYygiU1RBVEUiLCJZRUFSIiksCiAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSAid2l0aGluIiwKICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdCA9ICJ0d293YXlzIikKc3VtbWFyeShzdWJzZXRfMV9yZXN1bHQpCmBgYAoKSW5kZWVkLCB3ZSBjYW4gc2VlIHRoYXQgbm93IHdlIGhhdmUgYW4gdW5iYWxhbmNlZCBwYW5lbCB3aXRoIE4gPSAxMzk0IG9ic2VydmF0aW9ucyBpbnN0ZWFkIG9mIDEzOTUsIGFzIGV4cGVjdGVkLgoKTm93IHRoYXQgd2UgaGF2ZSBvdXIgc3Vic2V0cywgd2Ugd2FudCB0byB3cml0ZSBhIGZ1bmN0aW9uIHRvIGZpdCBhIHBhbmVsIHJlZ3Jlc3Npb24gdXNpbmcgYHBsbSgpYG9uIGVhY2ggc3Vic2V0cy4gU2VlIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYmxvb21iZXJnLXZhcGluZy1jYXNlLXN0dWR5Lyl7dGFyZ2V0PSJfYmxhbmsifSAgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gd3JpdGluZyBmdW5jdGlvbnMuCgpgYGB7cn0KZml0X25sc19vbl9ib290c3RyYXBfRE9OT0hVRSA8LSBmdW5jdGlvbihzdWJzZXQpewogICAgICAgICAgICAgICAgICAgIHBsbShWaW9sX2NyaW1lX3JhdGVfMWtfbG9nIH4KICAgICAgICAgICAgICAgICAgICAgICAgUlRDX0xBVyArCiAgICAgICAgICAgICAgICAgICAgICAgIFdoaXRlX01hbGVfMTVfdG9fMTlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBXaGl0ZV9NYWxlXzIwX3RvXzM5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgQmxhY2tfTWFsZV8xNV90b18xOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIEJsYWNrX01hbGVfMjBfdG9fMzlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBPdGhlcl9NYWxlXzE1X3RvXzE5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgT3RoZXJfTWFsZV8yMF90b18zOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIFVuZW1wbG95bWVudF9yYXRlICsKICAgICAgICAgICAgICAgICAgICAgICAgUG92ZXJ0eV9yYXRlICsgCiAgICAgICAgICAgICAgICAgICAgICAgIFBvcHVsYXRpb25fbG9nICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHBvbGljZV9wZXJfMTAwa19sYWcsCiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkYXRhLmZyYW1lKHN1YnNldCksCiAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSBjKCJTVEFURSIsIllFQVIiKSwKICAgICAgICAgICAgICAgICAgICAgICBtb2RlbCA9ICJ3aXRoaW4iLAogICAgICAgICAgICAgICAgICAgICAgZWZmZWN0ID0gInR3b3dheXMiKQp9CgpgYGAKCk5vdyB3ZSBjYW4gYXBwbHkgdGhpcyBmdW5jdGlvbiB0byBlYWNoIG9mIG91ciBzdWJzZXRzIHNpbXVsdGFuZW91c2x5IHVzaW5nIHRoZSBgbWFwKClgIGZ1bmN0aW9uIG9mIHRoZSBgcHVycnJgIHBhY2thZ2UuICAKCmBgYHtyLCBldmFsID0gRkFMU0V9CgpzdWJzZXRzX21vZGVsc19ET05PSFVFIDwtIG1hcChET05PSFVFX3N1YnNldHMsIGZpdF9ubHNfb25fYm9vdHN0cmFwX0RPTk9IVUUpCgpzdWJzZXRzX21vZGVsc19ET05PSFVFIDwtIHN1YnNldHNfbW9kZWxzX0RPTk9IVUUgJT4lCiAgbWFwKHRpZHkpCgpgYGAKCmBgYHtyLCBldmFsID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0Kc2F2ZShzdWJzZXRzX21vZGVsc19ET05PSFVFLCAKICAgICBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJET05PSFVFX3NpbXVsYXRpb25zLnJkYSIpKQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CmxvYWQoaGVyZTo6aGVyZSgiZGF0YSIsICJET05PSFVFX3NpbXVsYXRpb25zLnJkYSIpKQpgYGAKCgoKR3JlYXQhIE5vdyB3ZSB3YW50IHRvIGRvIHRoZSBzYW1lIHRoaW5nIGZvciB0aGUgTXVzdGFyZCBhbmQgTG90dCBkYXRhLgoKYGBge3J9CnNldC5zZWVkKDEyNCkKTE9UVF9zcGxpdHMgPC0gZF9wYW5lbF9MT1RUICU+JSBsb29fY3YoKQoKIyBUbyBnZXQgYWxsIHRoZSBkYXRhIHN1YnNldHM6CkxPVFRfc3Vic2V0cyA8LW1hcChwdWxsKExPVFRfc3BsaXRzLCBzcGxpdHMpLCB0cmFpbmluZykKYGBgCgoKV2UgbmVlZCB0byBjcmVhdGUgYSBkaWZmZXJlbnQgZnVuY3Rpb24gdG8gZml0IHRoZSBkYXRhIHRvIGFjY291bnQgZm9yIHRoZSBsYXJnZXIgbnVtYmVyIG9mIGRlbW9ncmFwaGljIHZhcmlhYmxlcy4gV2Ugd2lsbCB1c2UgdGhlIGZvcm11bGEgdGhhdCB3ZSBtYWRlIHByZXZpb3VzbHkuCgpgYGB7cn0KZml0X25sc19vbl9ib290c3RyYXBfTE9UVCA8LSBmdW5jdGlvbihzcGxpdCl7CiAgcGxtKExPVFRfZm1sYSwKICAgICAgZGF0YSA9IGRhdGEuZnJhbWUoc3BsaXQpLAogICAgICBpbmRleCA9IGMoIlNUQVRFIiwiWUVBUiIpLAogICAgICBtb2RlbCA9ICJ3aXRoaW4iLAogICAgICBlZmZlY3QgPSAidHdvd2F5cyIpCn0KYGBgCgoKCmBgYHtyLCBldmFsID0gRkFMU0V9CnN1YnNldHNfbW9kZWxzX0xPVFQgPC0gbWFwKExPVFRfc3Vic2V0cywgZml0X25sc19vbl9ib290c3RyYXBfTE9UVCkKCnN1YnNldHNfbW9kZWxzX0xPVFQgPC0gc3Vic2V0c19tb2RlbHNfTE9UVCAlPiUKICBtYXAodGlkeSkKYGBgCgoKYGBge3IsIGV2YWwgPSBGQUxTRSwgZWNobyA9IEZBTFNFfQpzYXZlKHN1YnNldHNfbW9kZWxzX0xPVFQsIAogICAgIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgIkxPVFRfc2ltdWxhdGlvbnMucmRhIikpCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRX0KbG9hZChoZXJlOjpoZXJlKCJkYXRhIiwgIkxPVFRfc2ltdWxhdGlvbnMucmRhIikpCmBgYAoKCk5vdyB3ZSB3aWxsIGNvbWJpbmUgdGhlIG91dHB1dCBzbyB0aGF0IHdlIGNhbiBtYWtlIGEgcGxvdCB0byB2aXN1YWxpemUgdGhlIHJlc3VsdHMgdGhhdCB3ZSBvYnRhaW5lZC4gRmlyc3QgbGV0J3MgbmFtZSBlYWNoIHN1YnNldCB0aGF0IHdlIGNyZWF0ZWQuCgpgYGB7cn0KbmFtZXMoc3Vic2V0c19tb2RlbHNfRE9OT0hVRSkgPC0gICAgIHBhc3RlMCgiRE9OT0hVRV8iLDE6bGVuZ3RoKHN1YnNldHNfbW9kZWxzX0RPTk9IVUUpKQoKbmFtZXMoc3Vic2V0c19tb2RlbHNfTE9UVCkgPC0gCnBhc3RlMCgiTE9UVF8iLDE6bGVuZ3RoKHN1YnNldHNfbW9kZWxzX0xPVFQpKQoKYGBgCgpOb3cgd2UgY2FuIGNvbWJpbmUgdGhlIHRpYmJsZXMgd2l0aGluIHRoZSBsaXN0IG9mIHRpYmJsZXMgZm9yIHRoZSBgc3Vic2V0c19tb2RlbHNfRE9OT0hVRWAgYW5kIGBzdWJzZXRzX21vZGVsc19MT1RUYCBkYXRhLgoKVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYGJpbmRfcm93cygpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHdpdGggdGhlIGAuaWQgPSAiSUQiYCBhcmd1bWVudCwgd2hpY2ggd2lsbCBjcmVhdGUgYSBuZXcgdmFyaWFibGUgY2FsbGVkIGBJRGAgdGhhdCB3aWxsIGxpc3QgdGhlIG5hbWUgb2YgdGhlIHRpYmJsZSB0aGUgZGF0YSBjYW1lIGZyb20uCgpUaGVuIHdlIHdpbGwgY29tYmluZSB0aGUgZGF0YSBmcm9tIGJvdGggdGhlIERvbm9odWUgYW5kIExvdHQgc2ltdWxhdGlvbnMuCgpgYGB7cn0KCnNpbXVsYXRpb25zX0RPTk9IVUUgPC0gc3Vic2V0c19tb2RlbHNfRE9OT0hVRSAlPiUKICBiaW5kX3Jvd3MoLmlkID0gIklEIikgJT4lCiAgbXV0YXRlKEFuYWx5c2lzID0gIkFuYWx5c2lzIDEiKQoKc2ltdWxhdGlvbnNfTE9UVCA8LSBzdWJzZXRzX21vZGVsc19MT1RUICU+JQogIGJpbmRfcm93cyguaWQgPSAiSUQiKSAlPiUKICBtdXRhdGUoQW5hbHlzaXMgPSAiQW5hbHlzaXMgMiIpCgpzaW11bGF0aW9ucyA8LSBiaW5kX3Jvd3Moc2ltdWxhdGlvbnNfRE9OT0hVRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXVsYXRpb25zX0xPVFQpCgpoZWFkKHNpbXVsYXRpb25zKQp0YWlsKHNpbXVsYXRpb25zKQpgYGAKCk5vdyB3ZSB3aWxsIG1ha2UgYSBqaXR0ZXIgcGxvdCB1c2luZyB0aGUgYGdlb21faml0dGVyKClgIGZ1bmN0aW9uIG9mIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMgb2YgdGhlIGBSVENfTEFXVFJVRWAgdmFyaWFibGUgZm9yIGVhY2ggc2ltdWxhdGlvbi4KClNpbmNlIHRoZXJlIGFyZSBtYW55IHZhcmlhYmxlcyBpbiBib3RoIGFuYWx5c2VzLCB3ZSB3aWxsIHVzZSB0aGUgYGZhY2V0X2dyaWQoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIHRvIGFsbG93IHVzIHRvIHNlcGFyYXRlIHRoZSBkYXRhIGZvciBlYWNoIGFuYWx5c2lzIGludG8gc3VicGxvdHMuIFRoZSBhcmd1bWVudCBgc2NhbGUgPSAiZnJlZV94ImAgYW5kIGBkcm9wID0gVFJVRWAgYWxsb3cgdXMgdG8gb25seSBpbmNsdWRlIHRoZSB2YXJpYWJsZXMgdGhhdCB3ZXJlIHByZXNlbnQgaW4gQW5hbHlzaXMgMSwgYXMgb3Bwb3NlZCB0byBlbXB0eSBzcG90cyBmb3IgdGhlIHZhcmlhYmxlcyB0aGF0IHdlcmUgaW4gQW5hbHlzaXMgMiBidXQgbm90IGluIEFuYWx5c2lzIDEuIFRoZSBgc3BhY2UgPSAiZnJlZSJgIGFyZ3VtZW50IHJlbW92ZXMgdGhlIGV4dHJhIHNwYWNlIGZyb20gdGhlIGRyb3BwZWQgdmFyaWFibGVzLiAKCiMjIyMgey5xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpXaGF0IGhhcHBlbnMgaWYgZG9uJ3QgdXNlIHRoZSBgZHJvcCA9IFRSVUVgIGFyZ3VtZW50IG9yIHRoZSBgc3BhY2UgPSAiZnJlZSJgIGFyZ3VtZW50PyAKCiMjIyMKCmBgYHtyfQpzaW11bGF0aW9uX3Bsb3QgPC0gc2ltdWxhdGlvbnMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gdGVybSwgeSA9IGVzdGltYXRlKSkgKyAKICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuMjUsCiAgICAgICAgICAgICAgd2lkdGggPSAwLjEpICsgCiAgZmFjZXRfZ3JpZCgufkFuYWx5c2lzLCBzY2FsZSA9ICJmcmVlX3giLCBzcGFjZSA9ICJmcmVlIiwgZHJvcCA9IFRSVUUpICsKICBsYWJzKHRpdGxlID0gIkNvZWZmaWNpZW50IGluc3RhYmlsaXR5IiwKICAgICAgIHN1YnRpdGxlID0gIkVzdGltYXRlcyBzZW5zaXRpdmUgdG8gb2JzZXJ2YXRpb24gZGVsZXRpb25zIiwKICAgICAgIHggPSAiVGVybSIsCiAgICAgICB5ID0gIkNvZWZmaWNpZW50IiwKICAgICAgIGNhcHRpb24gPSAiUmVzdWx0cyBmcm9tIHNpbXVsYXRpb25zIikgKyAKICB0aGVtZV9saW5lZHJhdygpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA3MCwgaGp1c3QgPSAxKSwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSkKCnNpbXVsYXRpb25fcGxvdAoKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlIHJhbmdlIG9mIGNvZWZmaWNpZW50IGVzdGltYXRlcyB3aGVuIG9ubHkgb25lIG9ic2VydmF0aW9uIGlzIHJlbW92ZWQgaXMgbXVjaCBsYXJnZXIgaW4gQW5hbHlzaXMgMiBmb3IgbmVhcmx5IGFsbCB2YXJpYWJsZXMsIGJ1dCBwYXJ0aWN1bGFybHkgZm9yIG1hbnkgb2YgdGhlIGFkZGl0aW9uYWwgZGVtb2dyYXBoaWMgdmFyaWFibGVzLgoKTGV0J3MgbWFrZSBhIHBsb3Qgc2hvd2luZyB0aGUgc3VtbWFyeSBvZiB0aGUgb3ZlcmFsbCBjb2VmZmljaWVudCBpbnN0YWJpbGl0eS4KClRvIGRvIHRoaXMgd2Ugd2lsbCBjYWxjdWxhdGUgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBjb2VmZmljaWVudCBlc3RpbWF0ZXMgZm9yIGVhY2ggdmFyaWFibGUgYWNyb3NzIGFsbCBvZiB0aGUgc2ltdWxhdGlvbnMuIFRodXMgIHdlIHdpbGwgZ3JvdXAgIGJ5ICB0aGUgYEFuYWx5c2lzYCBhbmQgIHRoZSBgdGVybWAgdmFyaWFibGVzIG5vdyB0aGF0IG91ciBkYXRhIGlzIGluIGxvbmcgZm9ybWF0LiBXZSB3aWxsIHVzZSB0aGUgYHNkKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RhdHNgIHBhY2thZ2UgdG8gY2FsY3VsYXRlIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24uCgpgYGB7cn0KY29lZmZfc2QgPC1zaW11bGF0aW9ucyAlPiUgCiAgZ3JvdXBfYnkoQW5hbHlzaXMsIHRlcm0pICU+JSAKICBzdW1tYXJpc2UoIlNEIiA9IHNkKGVzdGltYXRlKSkKYGBgCgpgYGB7cn0KbGlicmFyeShEVCkKRFQ6OmRhdGF0YWJsZShjb2VmZl9zZCkKYGBgCgpOb3cgd2Ugd2lsbCBtYWtlIGEgcGxvdCBvZiB0aGlzIGRhdGEuCgpgYGB7cn0Kc2ltdWxhdGlvbl9wbG90IDwtIGNvZWZmX3NkICU+JQogIGdncGxvdChhZXMoeCA9IEFuYWx5c2lzLCB5ID0gU0QpKSArIAogZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjEsIGFscGhhID0gMC41LCBzaXplID0gMikgKyAKICBsYWJzKHRpdGxlID0gIkNvZWZmaWNpZW50IGluc3RhYmlsaXR5IiwKICAgICAgIHN1YnRpdGxlID0gIkNvZWZmaWNpZW50IGVzdGltYXRlcyBhcmUgdW5zdGFibGUiLAogICAgICAgeCA9ICJUZXJtIiwKICAgICAgIHkgPSAiQ29lZmZpY2llbnQgRXN0aW1hdGUgXG4gU3RhbmRhcmQgRGV2aWF0aW9ucyIsCiAgICAgICBjYXB0aW9uID0gIlJlc3VsdHMgZnJvbSBzaW11bGF0aW9ucyIpICsgCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LCBjb2xvciA9ICJibGFjayIpLAogICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIpKQpzaW11bGF0aW9uX3Bsb3QKCmBgYAoKSGVyZSB3ZSBjYW4gY2xlYXJseSBzZWUgdGhhdCBvdmVyYWxsIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMgYXJlIG11Y2ggbGVzcyBzdGFibGUgaW4gQW5hbHlzaXMgMi4gVGhpcyBpcyBhIGNsZWFyIGluZGljYXRpb24gdGhhdCB3ZSBoYXZlIG11bHRpY29sbGluZWFyaXR5LgoKZnJvbSBNaWNoYWVsCmBgYHtyLCBldmFsID0gRkFMU0V9CnNpbXMgPC0gMjUwCgojIERPTk9IVUUKc2FtcHNfRE9OT0hVRSA8LSBsYXBwbHkocmVwKGRpbShET05PSFVFX0RGKVsxXS8yLCBzaW1zKSwKICAgICAgIGZ1bmN0aW9uKHgpRE9OT0hVRV9ERltzYW1wbGUobnJvdyhET05PSFVFX0RGKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSB4LCByZXBsYWNlID0gRkFMU0UpLF0pCgpmaXRfbmxzX29uX2Jvb3RzdHJhcF9ET05PSFVFIDwtIGZ1bmN0aW9uKHNwbGl0KXsKICBwbG0oVmlvbF9jcmltZV9yYXRlXzFrX2xvZyB+CiAgICAgICAgICAgICAgICAgICAgICAgIFJUQ19MQVcgKwogICAgICAgICAgICAgICAgICAgICAgICBXaGl0ZV9NYWxlXzE1X3RvXzE5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgV2hpdGVfTWFsZV8yMF90b18zOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIEJsYWNrX01hbGVfMTVfdG9fMTlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBCbGFja19NYWxlXzIwX3RvXzM5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgT3RoZXJfTWFsZV8xNV90b18xOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIE90aGVyX01hbGVfMjBfdG9fMzlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBVbmVtcGxveW1lbnRfcmF0ZSArCiAgICAgICAgICAgICAgICAgICAgICAgIFBvdmVydHlfcmF0ZSArIAogICAgICAgICAgICAgICAgICAgICAgICBQb3B1bGF0aW9uX2xvZyArIAogICAgICAgICAgICAgICAgICAgICAgICBwb2xpY2VfcGVyXzEwMGtfbGFnLAogICAgICBkYXRhID0gZGF0YS5mcmFtZShzcGxpdCksCiAgICAgIGluZGV4ID0gYygiU1RBVEUiLCJZRUFSIiksCiAgICAgIG1vZGVsID0gIndpdGhpbiIsCiAgICAgIGVmZmVjdCA9ICJ0d293YXlzIikKfQogIApzYW1wc19tb2RlbHNfRE9OT0hVRSA8LSBsYXBwbHkoc2FtcHNfRE9OT0hVRSwgZml0X25sc19vbl9ib290c3RyYXBfRE9OT0hVRSkKCnNhbXBzX21vZGVsc19ET05PSFVFIDwtIHNhbXBzX21vZGVsc19ET05PSFVFICU+JQogIG1hcCh0aWR5KQoKbmFtZXMoc2FtcHNfbW9kZWxzX0RPTk9IVUUpIDwtIHBhc3RlMCgiRE9OT0hVRV8iLDE6bGVuZ3RoKHNhbXBzX21vZGVsc19ET05PSFVFKSkKCnNpbXVsYXRpb25zX0RPTk9IVUUgPC0gc2FtcHNfbW9kZWxzX0RPTk9IVUUgJT4lCiAgYmluZF9yb3dzKC5pZCA9ICJJRCIpICU+JQogIG11dGF0ZShBbmFseXNpcyA9ICJBbmFseXNpcyAxIikKCiMjIE11c3RhcmQgYW5kIExvdHQKCnNhbXBzX0xPVFQgPC0gbGFwcGx5KHJlcChyb3VuZChkaW0oTE9UVF9ERilbMV0vMiksIHNpbXMpLAogICAgICAgZnVuY3Rpb24oeCkgTE9UVF9ERltzYW1wbGUobnJvdyhMT1RUX0RGKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSB4LCByZXBsYWNlID0gRkFMU0UpLF0pCgpmaXRfbmxzX29uX2Jvb3RzdHJhcF9MT1RUIDwtIGZ1bmN0aW9uKHNwbGl0KXsKICBwbG0oTE9UVF9mbWxhLAogICAgICBkYXRhID0gZGF0YS5mcmFtZShzcGxpdCksCiAgICAgIGluZGV4ID0gYygiU1RBVEUiLCJZRUFSIiksCiAgICAgIG1vZGVsID0gIndpdGhpbiIsCiAgICAgIGVmZmVjdCA9ICJ0d293YXlzIikKfQogIApzYW1wc19tb2RlbHNfTE9UVCA8LSBsYXBwbHkoc2FtcHNfTE9UVCwgZml0X25sc19vbl9ib290c3RyYXBfTE9UVCkKCnNhbXBzX21vZGVsc19MT1RUIDwtIHNhbXBzX21vZGVsc19MT1RUICU+JQogIG1hcCh0aWR5KQoKbmFtZXMoc2FtcHNfbW9kZWxzX0xPVFQpIDwtIHBhc3RlMCgiTE9UVF8iLDE6bGVuZ3RoKHNhbXBzX21vZGVsc19MT1RUKSkKCnNpbXVsYXRpb25zX0xPVFQgPC0gc2FtcHNfbW9kZWxzX0xPVFQgJT4lCiAgYmluZF9yb3dzKC5pZCA9ICJBbmFseXNpcyIpICU+JQogIG11dGF0ZShBbmFseXNpcyA9ICJBbmFseXNpcyAyIikKCnNpbXVsYXRpb25zIDwtIGJpbmRfcm93cyhzaW11bGF0aW9uc19ET05PSFVFLAogICAgICAgICAgICAgICAgICAgICAgICAgc2ltdWxhdGlvbnNfTE9UVCkKCnNpbXVsYXRpb25fcGxvdCA8LSBzaW11bGF0aW9ucyAlPiUKICBmaWx0ZXIodGVybT09IlJUQ19MQVdUUlVFIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gQW5hbHlzaXMsIHkgPSBlc3RpbWF0ZSkpICsgCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC4yNSwKICAgICAgICAgICAgICB3aWR0aCA9IDAuMSkgKyAKICBsYWJzKHRpdGxlID0gIkNvZWZmaWNpZW50IGluc3RhYmlsaXR5IiwKICAgICAgIHN1YnRpdGxlID0gIkVzdGltYXRlcyBzZW5zaXRpdmUgdG8gb2JzZXJ2YXRpb24gZGVsZXRpb25zIiwKICAgICAgIHggPSAiVGVybSIsCiAgICAgICB5ID0gIkNvZWZmaWNpZW50IiwKICAgICAgIGNhcHRpb24gPSAiUmVzdWx0cyBmcm9tIHNpbXVsYXRpb25zIikgKyAKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkKCnNpbXVsYXRpb25fcGxvdApgYGAKCgoKCiMjIyBWSUYKCkFub3RoZXIgd2F5IG9mIGV2YWx1YXRpbmcgdGhlIHByZXNlbmNlIGFuZCBzZXZlcml0eSBvZiBtdWx0aWNvbGxpbmVhcml0eSBpcyB0byBjYWxjdWxhdGUgdGhlIFt2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9yIChWSUYpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9WYXJpYW5jZV9pbmZsYXRpb25fZmFjdG9yKXt0YXJnZXQ9Il9ibGFuayJ9IC4gCgpBY2NvcmRpbmcgdG8gW1dpa2lwZWRpYV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVmFyaWFuY2VfaW5mbGF0aW9uX2ZhY3Rvcil7dGFyZ2V0PSJfYmxhbmsifToKCj5JdCBwcm92aWRlcyBhbiBpbmRleCB0aGF0IG1lYXN1cmVzIGhvdyBtdWNoIHRoZSB2YXJpYW5jZSAodGhlIHNxdWFyZSBvZiB0aGUgZXN0aW1hdGUncyBzdGFuZGFyZCBkZXZpYXRpb24pIG9mIGFuIGVzdGltYXRlZCByZWdyZXNzaW9uIGNvZWZmaWNpZW50IGlzIGluY3JlYXNlZCBiZWNhdXNlIG9mIGNvbGxpbmVhcml0eS4gCgo+IFRoZSB2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9yIChWSUYpIGlzIHRoZSAqKnF1b3RpZW50IG9mIHRoZSB2YXJpYW5jZSBpbiBhIG1vZGVsIHdpdGggbXVsdGlwbGUgdGVybXMgYnkgdGhlIHZhcmlhbmNlIG9mIGEgbW9kZWwgd2l0aCBvbmUgdGVybSBhbG9uZSoqLgoKVklGIHZhbHVlcyBjYW4gYmUgY2FsY3VsYXRlZCBmb3IgZWFjaCBleHBsYW5hdG9yeSB2YXJpYWJsZSBpbiBhIG1vZGVsIGJ5IHBlcmZvcm1pbmcgdGhlIGZvbGxvd2luZyBjYWxjdWxhdGlvbjoKCjEpIFJ1biBhbm90aGVyIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgKE9MUykgbGluZWFyIHJlZ3Jlc3Npb24gd2l0aCBvbmUgb2YgdGhlIGV4cGxhbmF0b3J5ICB2YXJpYWJsZXMgb2YgeW91ciBtb2RlbCBvZiBpbnRlcmVzdCAoJFhpJCkgYXMgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBhbmQga2VlcCB0aGUgcmVtYWluaW5nIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBhcyBleHBsYW5hdG9yeSB2YXJpYWJsZXMuCgpTbyBnZW5lcmljYWxseSBzcGVha2luZyBzYXkgdGhpcyBpcyBvdXIgbW9kZWw6CgokJFkgPSDOsl8wICsgzrJfMVhfMSArIM6yXzJYXzIgKyDOsl8zWF8zICQkCldlIGhhdmUgdGhyZWUgZXhwbGFuYXRvcnkgdmFyaWFibGVzICgkWF8xJCwgJFhfMiQsIGFuZCAkWF8zJCkuCgpJZiB3ZSB3YW50IHRvIGNhbGN1bGF0ZSB0aGUgVklGIHZhbHVlIGZvciAkWF8xJCB3ZSB3b3VsZCBuZWVkIHRvIHBlcmZvcm0gYW5vdGhlciBPTFMgbW9kZWwsIHdoZXJlICRYMSQgaXMgbm93IHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgZXhwbGFpbmVkIGJ5IHRoZSBvdGhlciBleHBsYW5hdG9yeSB2YXJpYWJsZXMuCgokJFhfMSA9IM6yXzAgKyAgzrJfMlhfMiArIM6yXzNYXzMgJCQKClRoZSBbJFJeMiQgY29lZmZpY2llbnQgb2YgZGV0ZXJtaW5hdGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ29lZmZpY2llbnRfb2ZfZGV0ZXJtaW5hdGlvbil7dGFyZ2V0PSJfYmxhbmsifSBhbHNvIGNhbGxlZCBSIHNxdWFyZWQgdmFsdWUgZnJvbSB0aGlzIHJlZ3Jlc3Npb24gaXMgdGhlbiB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgVklGIGFzIGZvbGxvd3M6CgokJFxmcmFjezF9ezEtUl57Mn19JCQKClRoZSAkUl4yJCB2YWx1ZSBpcyBpbiB0aGlzIGNhc2UgdGhlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgaW4gJFhfMSQgZXhwbGFpbmVkIGJ5IHRoZSBvdGhlciB2YXJpYWJsZXMgKCRYXzIkIGFuZCAkWF8zJCkuCgoKVklGIHZhbHVlcyBhcmUgdHlwaWNhbGx5IGNhbGN1bGF0ZWQgZm9yIGVhY2ggZXhwbGFuYXRvcnkgdmFyaWFibGUgd2hlbiBldmFsdWF0aW5nIG11bHRpY29sbGluZWFyaXR5IG9mIGEgbW9kZWwuCgpUaHVzIG92ZXJhbGwgdGhlIGNhbGN1bGF0aW9uIGlzOgokJFZJRl9pID0gXGZyYWN7MX17MS1SX2leezJ9fSQkCldoZXJlICRpJCBjb3JyZXNwb25kcyB0byBlYWNoIGV4cGxhbmF0b3J5IHZhcmlhYmxlLgoKClJlY2FsbCB0aGF0IGFjY29yZGluZyB0byBbV2lraXBlZGlhXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9WYXJpYW5jZV9pbmZsYXRpb25fZmFjdG9yKXt0YXJnZXQ9Il9ibGFuayJ9OgoKPiBUaGUgdmFyaWFuY2UgaW5mbGF0aW9uIGZhY3RvciAoVklGKSBpcyB0aGUgKipxdW90aWVudCBvZiB0aGUgdmFyaWFuY2UgaW4gYSBtb2RlbCB3aXRoIG11bHRpcGxlIHRlcm1zIGJ5IHRoZSB2YXJpYW5jZSBvZiBhIG1vZGVsIHdpdGggb25lIHRlcm0gYWxvbmUqKi4KClRoZSAkUl4yJCB2YWx1ZSByYW5nZXMgZnJvbSAwIHRvIDEuIFRodXMsIGlmIGEgdmFyaWF0aW9uIG9mIGEgdmFyaWFibGUgaXMgaGlnaGx5IGV4cGxhaW5lZCBieSB0aGUgb3RoZXIgdmFyaWFibGVzLCB0aGUgJFJeMiQgd2lsbCBhcHByb2FjaCAxLiBUaHVzIHRoZSBkZW5vbWluYXRvciBpbiB0aGUgVklGIGNhbGN1bGF0aW9uICQxLVJfaV57Mn0kICh3aGljaCBpcyBzb21ldGltZXMgcmVmZXJyZWQgdG8gYXMgdG9sZXJhbmNlKSB3aWxsIGJlIHNtYWxsZXIgYW5kIHRoZSBWSUYgdmFsdWUgd2lsbCBiZSBsYXJnZXIuCgpUaHVzLCAqKmhpZ2hlciBWSUYgdmFsZXMqKiBpbmRpY2F0ZSAqKm1vcmUgc2V2ZXJlIG11bHRpY29sbGluZWFyaXR5KiouIFR5cGljYWxseSBhIHRocmVzaG9sZCBvZiBhIHRvbGVyYW5jZSBvZiBsZXNzIHRoYW4gMC4xMCBhbmQvb3IgYSBWSUYgb2YgMTAgYW5kIGFib3ZlIGlzIHVzZWQgYXMgYSBydWxlIG9mIHRodW1iIHRvIGRldGVybWluZSBpZiB0aGUgcHJlc2VuY2Ugb2YgbXVsdGljb2xsaW5lYXJpdHkgbWlnaHQgYmUgcHJvYmxlbWF0aWMuCgpQbGVhc2Ugc2VlIHRoaXMgW2FydGljbGVdKGh0dHBzOi8vbGluay5zcHJpbmdlci5jb20vY29udGVudC9wZGYvMTAuMTAwNy9zMTExMzUtMDA2LTkwMTgtNi5wZGYpe3RhcmdldD0iX2JsYW5rIn0gZm9yIGEgdGhvcm91Z2ggZXhwbGFuYXRpb24gb2YgaG93IHRvIGludGVycHJldCBWSUYgdmFsdWVzIGFuZCBob3cgdG8gZGVjaWRlIHdoYXQgdG8gZG8gaWYgeW91ciBtb2RlbCBoYXMgaGlnaCBtdWx0aWNvbGxpbmVhcml0eS4KClNvIGhvdyBkbyB3ZSBjYWxjdWxhdGUgVklGIHZhbHVlcyBpbiBSPwoKV2UgY291bGQgZG8gdGhpcyBtYW51YWxseSBjcmVhdGluZyBtYW55IGxpbmVhciByZWdyZXNzaW9ucywgYnV0IHRoYXQgd291bGQgb2J2aW91c2x5IGJlIHRpbWUgY29uc3VtaW5nLiBMdWNraWx5LCB0aGUgYGNhcmAgcGFja2FnZSBoYXMgYSBmdW5jdGlvbiBjYWxsZWQgYHZpZigpYCB0aGF0IHdpbGwgY2FsY3VsYXRlIFZJRiB2YWx1ZXMuCgoKYXZvY2FkbzogSWRrIGlmIHRoaXMgaXMgdHJ1ZSBvciBpZiB3ZSBuZWVkIHRvIGRvIHdoYXQgTWljaGFlbCBkaWQ/Cmh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzIwMjgxMDU1L3Rlc3QtZm9yLW11bHRpY29sbGluZWFyaXR5LWluLXBhbmVsLWRhdGEtcgoKU2luY2UgVklGIHZhbHVlcyBhcmUgY2FsY3VsYXRlZCB1c2luZyBvbmx5IHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMsIHdlIGRvbid0IG5lZWQgdG8gd29ycnkgYWJvdXQgdGhlIGVmZmVjdCBvZiB0aW1lIGFuZCBpbmRpdmlkdWFscyBpbiBvdXIgY2FsY3VsYXRpb24sIHRodXMgd2Ugd2lsbCB1c2UgdGhlIHBvb2xlZCBtb2RlbC4gT3RoZXJ3aXNlLCB0aGUgYHZpZigpYCBmdW5jdGlvbiBpcyBpbmNvbXBhdGlibGUgd2l0aCB0aGUgb3V0cHV0IGZyb20gdGhlIGBwbG0oKWAgZnVuY3Rpb24uCgpUaGVuIHdlIHdpbGwgY3JlYXRlIG5pY2VyIGxvb2tpbmcgb3V0cHV0IG9mIHRoZSBkYXRhIHVzaW5nIHRoZSBgYXNfdGliYmxlKClgZnVuY3Rpb24gb2YgdGhlIGB0aWJibGVgIHBhY2thZ2UgdG8gY3JlYXRlIGEgdGliYmxlIGFuZCBhZGQgdGhlIHZhcmlhYmxlIG5hbWVzIGFzIGFub3RoZXIgY29sdW1uLgoKYGBge3J9Cgp2aWZfRE9OT0hVRSA8LSB2aWYoRE9OT0hVRV9wb29sX21vZGVsKQp2aWZfRE9OT0hVRSAKCnZpZl9ET05PSFVFIDwtIHZpZl9ET05PSFVFICU+JQogIGFzX3RpYmJsZSgpICU+JQogIGNiaW5kKC4sIG5hbWVzKHZpZl9ET05PSFVFKSkKICAKY29sbmFtZXModmlmX0RPTk9IVUUpIDwtIGMoIlZJRiIsICJWYXJpYWJsZSIpCgp2aWZfRE9OT0hVRQpgYGAKCk5vdyB3ZSB3aWxsIGRvIHRoZSBzYW1lIGZvciB0aGUgTXVzdGFyZCBhbmQgTG90dCBkYXRhOgoKYGBge3J9CkxPVFRfcG9vbF9tb2RlbCA8LXBsbShMT1RUX2ZtbGEsCiAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsID0gInBvb2xpbmciLAogICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRfcGFuZWxfTE9UVCkKCnZpZl9MT1RUIDwtIHZpZihMT1RUX3Bvb2xfbW9kZWwpCgoKdmlmX0xPVFQgPC0gdmlmX0xPVFQgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgY2JpbmQoLiwgbmFtZXModmlmX0xPVFQpKQpjb2xuYW1lcyh2aWZfTE9UVCkgPC0gYygiVklGIiwgIlZhcmlhYmxlIikKYGBgCgoKYGBge3J9CgpEVDo6ZGF0YXRhYmxlKHZpZl9MT1RUKQpgYGAKCldlIGNhbiBzZWUgdGhhdCBzb21lIG9mIHRoZSBWSUYgdmFsdWVzIGFyZSB2ZXJ5IGhpZ2ghCgoKCmF2b2NhZG86RnJvbSBNaWNoYWVsOiBoZSBjYWxjdWxhdGVkIHRoZSB0aW1lLWRlbWVhbmVkIHJlc3BvbnNlIHZhcmlhYmxlIGJhc2VkIG9uIHRoaXMgbGluazoKaHR0cDovL2thcnRodXIub3JnLzIwMTkvaW1wbGVtZW50aW5nLWZpeGVkLWVmZmVjdHMtcGFuZWwtbW9kZWxzLWluLXIuaHRtbAoKSWRrIGlmIHdlIG5lZWQgdG8vc2hvdWxkIGRvIHRoaXMuIFRoZSB2YWx1ZXMgYXJlIGRpZmZlcmVudC4tIGxvd2VyIGluIGdlbmVyYWwuSWYgc28gdGhvdWdoIHRoaXMgaXMgaG93IG9uZSB3b3VsZCBkbyBpdC4KClRoaXMgYHZpZigpYCBmdW5jdGlvbiBpcyBub3QgY29tcGF0aWJsZSB3aXRoIHRoZSBgcGxtYCBwYWNrYWdlIHBhbmVsIGRhdGEgZnJhbWVzIGFuZCBsaW5lYXIgbW9kZWwgb3V0cHV0cywgdGh1cyB3ZSBuZWVkIHRvIGNyZWF0ZSBhIGRlc2lnbiBtYXRyaXggd2l0aCB0aGUgYHBsbWAgcGFja2FnZSB1c2luZyB0aGUgYFdpdGhpbigpYCBmdW5jdGlvbiBhbmQgdGhlbiB1c2UgdGhlIGBsbSgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0YXRzYCBwYWNrYWdlIHRvIGZpdCB0aGUgbW9kZWwuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpkZXNpZ24ubWF0cml4IDwtIGFzLmRhdGEuZnJhbWUobW9kZWwubWF0cml4KERPTk9IVUVfT1VUUFVUKSkKI2Rlc2lnbi5tYXRyaXg8LURPTk9IVUVfT1VUUFVUW1sibW9kZWwiXV0KZGVzaWduLm1hdHJpeCRWaW9sX2NyaW1lX3JhdGVfMWtfbG9nIDwtIHBsbTo6V2l0aGluKAogIGRfcGFuZWxfRE9OT0hVRSRWaW9sX2NyaW1lX3JhdGVfMWtfbG9nKQoKbG1fRE9OT0hVRSA8LSBsbShWaW9sX2NyaW1lX3JhdGVfMWtfbG9nIH4KICAgICAgICAgICAgICAgICAgICAgICAgUlRDX0xBV1RSVUUgKyAjIGxvZ2ljYWwgY2xhc3MgY2hhbmdlcyB2YXJpYWJsZSBuYW1lIGFmdGVyIGluaXRhbCBtb2RlbAogICAgICAgICAgICAgICAgICAgICAgICBXaGl0ZV9NYWxlXzE1X3RvXzE5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgV2hpdGVfTWFsZV8yMF90b18zOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIEJsYWNrX01hbGVfMTVfdG9fMTlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBCbGFja19NYWxlXzIwX3RvXzM5X3llYXJzICsKICAgICAgICAgICAgICAgICAgICAgICAgT3RoZXJfTWFsZV8xNV90b18xOV95ZWFycyArCiAgICAgICAgICAgICAgICAgICAgICAgIE90aGVyX01hbGVfMjBfdG9fMzlfeWVhcnMgKwogICAgICAgICAgICAgICAgICAgICAgICBVbmVtcGxveW1lbnRfcmF0ZSArCiAgICAgICAgICAgICAgICAgICAgICAgIFBvdmVydHlfcmF0ZSArIAogICAgICAgICAgICAgICAgICAgICAgICBQb3B1bGF0aW9uX2xvZyArCiAgICAgICAgICAgICAgIHBvbGljZV9wZXJfMTAwa19sYWcsCiAgICAgICAgICAgICBkYXRhID0gZGVzaWduLm1hdHJpeCkKCgp2aWZfRE9OT0hVRSA8LSB2aWYobG1fRE9OT0hVRSkKCnZpZl9ET05PSFVFCgp2aWZfRE9OT0hVRSA8LSB2aWZfRE9OT0hVRSAlPiUKICBhc190aWJibGUoKSAlPiUKICBjYmluZCguLCBuYW1lcyh2aWZfRE9OT0hVRSkpICU+JQogIGFzX3RpYmJsZSgpCiAgCmNvbG5hbWVzKHZpZl9ET05PSFVFKSA8LSBjKCJWSUYiLCAiVmFyaWFibGUiKQpgYGAKCmBgYHtyLCBldmFsID0gRkFMU0V9CmRlc2lnbi5tYXRyaXggPC0gYXMuZGF0YS5mcmFtZShtb2RlbC5tYXRyaXgoTE9UVF9PVVRQVVQpKQoKZGVzaWduLm1hdHJpeCRWaW9sX2NyaW1lX3JhdGVfMWtfbG9nIDwtIHBsbTo6V2l0aGluKAogIGRfcGFuZWxfTE9UVCRWaW9sX2NyaW1lX3JhdGVfMWtfbG9nKQoKTE9UVF92YXJpYWJsZXNfb2xzIDwtIExPVFRfREYgJT4lCiAgZHBseXI6OnNlbGVjdChSVENfTEFXLAogICAgICAgICAgICAgICAgY29udGFpbnMoYygiV2hpdGUiLCJCbGFjayIsIk90aGVyIikpLAogICAgICAgICAgICAgICAgVW5lbXBsb3ltZW50X3JhdGUsCiAgICAgICAgICAgICAgICBQb3ZlcnR5X3JhdGUsCiAgICAgICAgICAgICAgICBQb3B1bGF0aW9uX2xvZywKICAgICAgICAgICAgICAgIHBvbGljZV9wZXJfMTAwa19sYWcpICU+JQogIGNvbG5hbWVzKCkgJT4lCiAgc3RyX3JlcGxhY2UoIlJUQ19MQVciLCAiUlRDX0xBV1RSVUUiKSAjIGxvZ2ljYWwgY2xhc3MgY2hhbmdlcyB2YXJpYWJsZSBuYW1lIGFmdGVyIGluaXRhbCBtb2RlbAoKTE9UVF9mbWxhX29scyA8LSBhcy5mb3JtdWxhKHBhc3RlKCJWaW9sX2NyaW1lX3JhdGVfMWtfbG9nIH4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShMT1RUX3ZhcmlhYmxlc19vbHMsIGNvbGxhcHNlID0gIiArICIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgKQoKbG1fTE9UVCA8LSBsbShMT1RUX2ZtbGFfb2xzLAogICAgICAgICAgICAgZGF0YSA9IGRlc2lnbi5tYXRyaXgpCgp2aWYobG1fTE9UVCkKCnZpZl9MT1RUIDwtIHZpZihsbV9MT1RUKQoKdmlmX0xPVFQgPC0gdmlmX0xPVFQgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgY2JpbmQoLiwgbmFtZXModmlmX0xPVFQpKSAlPiUKICBhc190aWJibGUoKQogIApjb2xuYW1lcyh2aWZfTE9UVCkgPC0gYygiVklGIiwgIlZhcmlhYmxlIikKCm1heF92aWZfTE9UVCA8LSBtYXgodmlmKGxtX0xPVFQpKQpgYGAKCgpOb3cgd2Ugd2lsbCBtYWtlIGEgcGxvdCBvZiB0aGUgVklGIHZhbHVlcyBmb3IgYm90aCBhbmFseXNlczoKCmBgYHtyfQoKdmlmX0RPTk9IVUUkQW5hbHlzaXMgPC0gIkFuYWx5c2lzIDEiCnZpZl9MT1RUJEFuYWx5c2lzIDwtICJBbmFseXNpcyAyIgoKdmlmX2RmIDwtIHJiaW5kKHZpZl9ET05PSFVFLAogICAgICAgICAgICAgICAgdmlmX0xPVFQpCgp2aWZfcGxvdCA8LSB2aWZfZGYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gQW5hbHlzaXMsIHkgPSBWSUYpKSArCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjEsIGFscGhhID0gMC41LCBzaXplID0gMikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEwLCBjb2xvciA9ICJyZWQiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gJ2xvZzEwJywKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygxLDEwMDApKSArCiAgbGFicyh0aXRsZSA9ICJWYXJpYW5jZSBpbmZsYXRpb24gZmFjdG9ycyIpICsgCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIikpCgp2aWZfcGxvdApgYGAKV2UgY2FuIHNlZSB0aGF0IGJvdGggYW5hbHlzZXMgaGF2ZSBzb21lIHZhcmlhYmxlcyB3aXRoIHJlbGF0aXZlbHkgaGlnaCBtdWx0aWNvbGxpbmVhcml0eSwgaG93ZXZlciBhbmFseXNpcyAyIGhhcyB2YXJpYWJsZXMgd2l0aCB2ZXJ5IGhpZ2ggbXVsdGljb2xsaW5lYXJpdHkuCgpJbiBtYW55IGNhc2VzIGl0IHdvdWxkIGJlIGFkdmlzYWJsZSB0byByZW1vdmUgb25lIG9yIG1vcmUgb2YgdGhlc2UgdmFyaWFibGVzIGFuZCByZWFzc2VzcyB0aGUgVklGIHZhbHVlcy4gVGhlcmUgYXJlIGFsc28gb3RoZXIgb3B0aW9ucywgc3VjaCBhcyBbcmlkZ2UgcmVncmVzc2lvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVGlraG9ub3ZfcmVndWxhcml6YXRpb24pe3RhcmdldD0iX2JsYW5rIn0uIEhvd2V2ZXIsIGJvdGggb2YgdGhlc2Ugb3B0aW9ucyBuZWVkIHRvIGJlIGRvbmUgd2l0aCBjYXJlIGFzIHRoZXkgY2FuIGFsc28gaW50cm9kdWNlIGJpYXMgaW50byB0aGUgbW9kZWwuCgpJbiBhbnkgY2FzZSB0aGUgcHJlc2VuY2Ugb2YgbXVsdGljb2xsaW5lYXJpdHkgc2hvdWxkIGVuY291cmFnZSBmdXJ0aGVyIGludmVzdGlnYXRpb24gYWJvdXQgdGhlIGRlc2lnbiBvZiB0aGUgbW9kZWwsIGFzIHRoZSByZXN1bHRzIG1heSBub3QgYmUgcmVsaWFibGUgZHVlIHRvIHRoZSBpbmNyZWFzZWQgbGV2ZWwgb2YgaW5zdGFiaWxpdHkgb2YgdGhlIGNvZWZmaWNpZW50cyBlc3RpbWF0ZXMuCgpTZWUgdGhpcyB0aGlzIFthcnRpY2xlXShodHRwczovL2xpbmsuc3ByaW5nZXIuY29tL2NvbnRlbnQvcGRmLzEwLjEwMDcvczExMTM1LTAwNi05MDE4LTYucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBhIGRldGFpbGVkIGRpc2N1c3Npb24gYWJvdXQgd2hhdCB0byBjb25zaWRlciB3aGVuIHlvdXIgbW9kZWwgaGFzIHZhcmlhYmxlcyB3aXRoIGhpZ2ggVklGIHZhbHVlcy4gCgoKIyAqKkRhdGEgVmlzdWFsaXphdGlvbioqCioqKiAKCk5vdyBsZXRzIG1ha2UgYSBwbG90IHRoYXQgc3VtbWFyaXplcyBhbGwgb2Ygb3VyIGZpbmRpbmdzLgoKV2Ugd2lsbCB1c2UgdGhlIGBjb3dwbG90YCBwYWNrYWdlIHRvIHB1dCBvdXIgcGxvdHMgdG9nZXRoZXIuIAoKV2Ugd2lsbCB1c2UgdGhlIGBnZ2RyYXcoKWAgZnVuY3Rpb24gb2YgdGhpcyBwYWNrYWdlLiBUaGlzIGFsbG93cyB5b3UgdG8gYWRkIGxhYmVscyBhbmQgb3RoZXIgcGxvdCBhc3BlY3RzIG9uIHRvcCBvZiBleGlzdGluZyBwbG90cy4gVGh1cyBpZiB3ZSB3YW50IHRvIGFkZCBhIHRpdGxlIGVsZW1lbnQgdG8gb3VyIG92ZXJhbGwgcGxvdCB0aGF0IHdlIHdpbGwgYWRkIHRvIGEgY29tYmluZWQgcGxvdCBvZiBvdXIgZXhpc3RpbmcgcGxvdHMgd2UgY2FuIHVzZSBgZ2dkcmF3KClgIHRvIHN0YXJ0IGFuZCB0aGVuIHRoZSBgZHJhd19sYWJlbCgpYCBmdW5jdGlvbiB0byBhZGQgdGV4dC4KCgpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KdGl0bGVfcGxvdHMgPC0gZ2dkcmF3KCkgKyAKICBkcmF3X2xhYmVsKAogICAgIk11bHRpY29sbGluZWFyaXR5IGFuZCBpdHMgZWZmZWN0cyIsCiAgICBmb250ZmFjZSA9ICdib2xkJywKICAgIHNpemU9MTgsCiAgICB4ID0gMCwKICAgIGhqdXN0ID0gLTAuMDEKICApICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKdGl0bGVfcGxvdHMKY2xhc3ModGl0bGVfcGxvdHMpCmBgYAoKQXMgeW91IGNhbiBzZWUgd2Uga25vdyBoYXZlIHBsb3Qgb2JqZWN0IHRoYXQganVzdCBoYXMgdGhlIHRleHQgYCJNdWx0aWNvbGxpbmVhcml0eSBhbmQgaXRzIGVmZmVjdHMiYC4KCk5vdyB3ZSB3aWxsIGNyZWF0ZSBhIHN1YnRpdGxlIGluIHRoZSBzYW1lIHdheS4KCmBgYHtyfQoKZm9yd2FyZCA8LSBnZ2RyYXcoKSArIAogIGRyYXdfbGFiZWwoCiAgICAiQW5hbHlzaXMgMTogNiBkZW1vZ3JhcGhpYyB2YXJpYWJsZXNcbkFuYWx5c2lzIDI6IDM2IGRlbW9ncmFwaGljIHZhcmlhYmxlcyIsCiAgICBmb250ZmFjZSA9ICdib2xkJywKICAgIHNpemU9MTAsCiAgICB4ID0gMCwKICAgIGhqdXN0ID0gLTAuMDIKICApICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKZm9yd2FyZApgYGAKCk5vdyB3ZSB3aWxsIHJlY3JlYXRlIG91ciBjb3JyZWxhdGlvbiBwbG90cyB3aXRoIHNvbWUgc2xpZ2h0IGFsdGVyYXRpb25zLiBXZSB3YW50IHRvIHJlbW92ZSBvdXIgbGFiZWxzLCBiZWNhdXNlIHRoZXkgd2lsbCBiZSB0b28gc21hbGwgdG8gc2VlIHdoZW4gd2UgY29tYmluZSBvdXIgcGxvdHMuIFRvIGRvIHRoaXMgd2Ugd2lsbCB1c2UgdGhlIGB0aGVtZV92b2lkKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4KCk5vdGUgdGhhdCBiZWNhdXNlIHdlIGFyZSBsYXllcmluZyBnZ3Bsb3QyIG9iamVjdHMgd2UgY2FuJ3QgdXNlIHRoZSBgJT4lYCBwaXBlIHRvIHN0YXJ0IHdpdGggdGhlIGV4aXN0aW5nIGNvcnJlbGF0aW9uIHBsb3RzLgoKYGBge3J9Cgpjb3JyX21hdF9ET05PSFVFIDwtIGNvcnJfbWF0X0RPTk9IVUUgKwogIHRoZW1lX3ZvaWQoKSArIAogIHRoZW1lKHBsb3QudGl0bGU9IGVsZW1lbnRfdGV4dChzaXplID0gOCwgY29sb3IgPSAiYmxhY2siKSkgKwogIGxhYnModGl0bGUgPSAiQW5hbHlzaXMgMSIpIAoKY29ycl9tYXRfTE9UVCA8LSBjb3JyX21hdF9MT1RUICsKICB0aGVtZV92b2lkKCkgKyAKICB0aGVtZShwbG90LnRpdGxlPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgsY29sb3IgPSAiYmxhY2siKSkgKwogIGxhYnModGl0bGUgPSAiQW5hbHlzaXMgMiIpIApgYGAKCk9LIHdlIHdhbnQgdG8gYXJyYW5nZSBvdXIgY29ycmVsYXRpb24gcGxvdHMgdG8gYmUgaW4gdGhlIHRvcCByb3cgb2Ygb3VyIGxhcmdlciBwbG90LiBOb3cgd2Ugd2lsbCB1c2UgdGhlIGBwbG90X2dyaWQoKWAgZnVuY3Rpb24gdG8gYXJyYW5nZSB0aGUgcGxvdHMuCgpgYGB7cn0Kcm93X0EgPC0gcGxvdF9ncmlkKGNvcnJfbWF0X0RPTk9IVUUsCiAgICAgICAgICAgICAgICAgICBjb3JyX21hdF9MT1RULAogICAgICAgICAgICAgICAgICAgbnJvdyA9IDEpCnJvd19BCmBgYAoKCk5pY2UhIFdlIGhhdmUgY29tYmluZWQgcGxvdHMhCgoKTm93IGxldCdzIGFkZCBhIHRpdGxlIGZvciB0aGVzZSBwbG90cy4KCmBgYHtyfQoKdGl0bGVfQSA8LSBnZ2RyYXcoKSArIAogIGRyYXdfbGFiZWwoCiAgICAiQ29ycmVsYXRpb24gYmV0d2VlbiB2YXJpYWJsZXMgY2FuIGluZHVjZSBtdWx0aWNvbGxpbmVhcml0eSIsCiAgICBmb250ZmFjZSA9ICdib2xkJywKICAgIHNpemU9MTQsCiAgICB4ID0gMCwKICAgIGhqdXN0ID0gLTAuMDEKICApICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKcGxvdF9BIDwtIHBsb3RfZ3JpZCh0aXRsZV9BLAogICAgICAgICAgICAgICAgICAgIHJvd19BLAogICAgICAgICAgICAgICAgICAgIG5jb2wgPSAxLAogICAgICAgICAgICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygwLjEsMSkpCmBgYAoKCkZvciBvdXIgc2Vjb25kIHJvdyBpbiBvdXIgbGFyZ2VyIHBsb3Qgd2Ugd2FudCB0byBoYXZlIHRoZSBmb3JtdWxhIGZvciBjYWxjdWxhdGluZyBWSUYgdmFsdWVzIG9uIHRoZSBsZWZ0IGFuZCB0aGUgcGxvdCB0aGF0IHdlIGNyZWF0ZWQgcHJldmlvdXNseSBzaG93aW5nIFZJRiB2YWx1ZXMgb24gdGhlIHJpZ2h0LgoKRmlyc3Qgd2Ugd2lsbCBjcmVhdGUgYSBwbG90IG9iamVjdCB0aGF0IGp1c3QgaGFzIHRoZSBmb3JtdWxhLgoKVG8gZG8gc28gd2UgYXJlIGdvaW5nIHRvIGNyZWF0ZSBhIHBsb3Qgd2l0aCBhIGxhcmdlIGxhYmVsIGluIHRoZSBtaWRkbGUgY29udGFpbmluZyB0aGUgZm9ybXVsYS4gVGhlbiB3ZSB3aWxsIHVzZSB0aGUgYHRoZW1lX3ZvaWQoKWAgZnVuY3Rpb24gYWdhaW4gdG8gcmVtb3ZlIHRoZSBheGlzIGxhYmVscyBhbmQgYmFja2dyb3VuZC4KClRvIGNyZWF0ZSBvdXIgcGxvdCB3ZSB3aWxsIGZpcnN0IHBsb3QgdmFsdWVzIGZyb20gMS0xMCBmb3IgYm90aCB0aGUgeCBhbmQgeSBheGlzLCBhbGxvd2luZyB1cyB0byBjZW50ZXIgdGhlIGZvcm11bGEgYXQgeCBhbmQgeSB2YWx1ZXMgb2YgNS4KClRvIHR5cGUgdGhlIGZvcm1hbCB3ZSBuZWVkIHRvIHVzZSBbTGFUZVggbWF0aGVtYXRpY2FsIG5vdGF0aW9uXShodHRwczovL3d3dy5jYWx2aW4uZWR1L35ycHJ1aW0vY291cnNlcy9zMzQxL1MxNy9mcm9tLWNsYXNzL01hdGhpblJtZC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9LgoKVGhlIHN0YXJ0IGFuZCBlbmQgb2YgaW5saW5lIG1hdGhlbWF0aWNhbCBmb3JtdWxhcyBhcmUgc3BlY2lmaWVkIHVzaW5nIGRvbGxhciBzaWducyAoYCRgKS4gICAKU3Vic2NyaXB0cyBhcmUgd3JpdHRlbiBieSB1c2luZyBhbiB1bmRlcnNjb3JlIChgX2ApIGFuZCBicmFja2V0cyAoYHt9YCkgaW5kaWNhdGUgdGhlIHN0YXJ0IGFuZCBlbmQgb2YgdGhlIHN1YnNjcmlwdC4gICAKCkZyYWN0aW9ucyBhcmUgaW5kaWNhdGVkIHVzaW5nIGBcZnJhY3tub21pbmF0b3J9e2Rlbm9taW5hdG9yfWAuCgpTdXBlcnNjcmlwdHMgYXJlIGNyZWF0ZWQgdXNpbmcgdGhlIGNhcnJvdCBzeW1ib2wgKGBeYCkgYW5kIGJyYWNrZXRzIChge31gKSBpbmRpY2F0ZSB0aGUgc3RhcnQgYW5kIGVuZCBvZiB0aGUgc3VwZXJzY3JpcHQuICAgCgpHcmVlayBsZXR0ZXJzICBhcmUgY3JlYXRlZCBieSB1c2luZyBgXGJldGFgCgpJbiB0aGUgY2FzZSBvZiB0aGUgZnJhY3Rpb24gYW5kIEdyZWVrIGxldHRlcnMgYW4gYWRkaXRpb25hbCBgXGAgaXMgbmVlZGVkIGluIHRoZSBgVGV4KClgIGZ1bmN0aW9uLgoKV2Ugd2lsbCB1c2UgdGhlIGBUZVgoKWAgZnVuY3Rpb24gb2YgdGhlIGBsYXRleDJleHBgIHBhY2thZ2UgdG8gY29udmVydCBvdXIgTGFUZVggc3RyaW5nIHRvIGEgW3Bsb3RtYXRoIGV4cHJlc3Npb25dKGh0dHBzOi8vc3RhdC5ldGh6LmNoL1ItbWFudWFsL1ItZGV2ZWwvbGlicmFyeS9nckRldmljZXMvaHRtbC9wbG90bWF0aC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IChhIG1hdGhlbWF0aWNhbCBub3RhdGlvbiBpbiBSIHRvIGJlIHVzZWQgaW4gcGxvdHMuKQoKYGBge3J9CmVtcHR5X2RmIDwtIGNiaW5kKGMoMToxMCksYygxOjEwKSkgJT4lCiAgYXMuZGF0YS5mcmFtZSgpCgpjb2xuYW1lcyhlbXB0eV9kZikgPC0gYygiWCIsICJZIikKCnBsb3RfQjEgPC0gZ2dwbG90KGVtcHR5X2RmLCBhZXMoeCA9IFgsIHkgPSBZKSkgKwogICBhbm5vdGF0ZSgidGV4dCIsCiAgICAgICAgICAgeD01LAogICAgICAgICAgIHk9OCwKICAgICAgICAgICBsYWJlbCA9IFRlWCgiJFhfezF9ID0gXFxiZXRhX3swfSArIFxcYmV0YV97Mn1YX3syfSArIFxcYmV0YV97M31YX3szfS4uLitcXGJldGFfe2t9WF97a30kIiksCiAgICAgICAgICAgc2l6ZSA9IDcpKyB5bGltKDAsMTApK3hsaW0oMCwxMCkrCiAgIGFubm90YXRlKCJ0ZXh0IiwKICAgICAgICAgICB4PTUuOSwKICAgICAgICAgICB5PTUuNSwKICAgICAgICAgICBsYWJlbCA9IFRlWCgiJFJeezJ9JCIpLAogICAgICAgICAgIHNpemUgPSA3KSsgeWxpbSgwLDEwKSt4bGltKDAsMTApKwpnZW9tX3NlZ21lbnQoYWVzKHggPSA1LCB5ID0gNiwgeGVuZCA9IDUsIHllbmQgPSA0LjUpLAogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGFuZ2xlID0gNDUsIGVuZHMgPSAibGFzdCIsIHR5cGUgPSAib3BlbiIpLAogICAgICAgICAgICAgICBzaXplID0gMS44LAogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgIGxpbmVlbmQgPSAiYnV0dCIsCiAgICAgICAgICAgICAgIGxpbmVqb2luID0gIm1pdHJlIikgKwogIGFubm90YXRlKCJ0ZXh0IiwKICAgICAgICAgICB4PTUsCiAgICAgICAgICAgeT0yLAogICAgICAgICAgIGxhYmVsID0gVGVYKCIkVklGX3tpfSA9IFxcZnJhY3sxfXsxLVJfe2l9XnsyfX0kIiksCiAgICAgICAgICAgc2l6ZSA9IDcpCgogIAogCiAgCnBsb3RfQjEKCnBsb3RfQjEgPC1wbG90X0IxKwogIHRoZW1lX3ZvaWQoKQoKcGxvdF9CMQpgYGAKCk5vdyB3ZSB3aWxsIGNvbWJpbmUgdGhpcyB3aXRoIHRoZSBWSUYgcGxvdC4KCmBgYHtyfQpwbG90X0IyIDwtIHZpZl9wbG90ICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTgpKQoKcm93X0IgPC0gcGxvdF9ncmlkKHBsb3RfQjEsCiAgICAgICAgICAgICAgICAgICBwbG90X0IyLAogICAgICAgICAgICAgICAgICAgbnJvdyA9IDEpCgp0aXRsZV9CIDwtIGdnZHJhdygpICsgCiAgZHJhd19sYWJlbCgKICAgICJWYXJpYW5jZSBpbmZsYXRpb24gZmFjdG9ycyBjYW4gYmUgdXNlZCB0byBpZGVudGlmeSBtdWx0aWNvbGxpbmVhcml0eSB3aGVuIHByZXNlbnQiLAogICAgZm9udGZhY2UgPSAnYm9sZCcsCiAgICBzaXplID0gMTQsCiAgICB4ID0gMCwKICAgIGhqdXN0ID0gLS4wMSwKICApICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKcGxvdF9CIDwtIHBsb3RfZ3JpZCh0aXRsZV9CLAogICAgICAgICAgICAgICAgICAgIHJvd19CLAogICAgICAgICAgICAgICAgICAgIG5jb2wgPSAxLAogICAgICAgICAgICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygwLjEsMSkpCgpwbG90X0IKYGBgCgoKTm93IGZvciB0aGUgdGhpcmQgcm93IHdlIHdhbnQgdG8gaW5jbHVkZSB0aGUgYGNvbXBhcmluZ19hbmFseXNlc19wbG90YCBhbmQgdGhlIGBzaW11bGF0aW9uX3Bsb3RgLgoKYGBge3J9CnBsb3RfQzEgPC0gY29tcGFyaW5nX2FuYWx5c2VzX3Bsb3QgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgbGFicyh0aXRsZSA9ICJJbnRyb2R1Y2VzIGJpYXMgdG8gZXN0aW1hdGVzIiwKICAgICAgIHN1YnRpdGxlID0gIkJpYXMgaW50cm9kdWNlZCBjYW4gY2hhbmdlIGRpcmVjdGlvbiBvZiBlc3RpbWF0ZSIpCgpwbG90X0MyIDwtIHNpbXVsYXRpb25fcGxvdCArCiAgbGFicyh0aXRsZSA9ICJSZWR1Y2VzIHByZWNpc2lvbiBpbiBlc3RpbWF0ZXMiKQoKcm93X0MgPC0gcGxvdF9ncmlkKHBsb3RfQzEsCiAgICAgICAgICAgICAgICAgICBwbG90X0MyLAogICAgICAgICAgICAgICAgICAgbnJvdyA9IDEpCgp0aXRsZV9DIDwtIGdnZHJhdygpICsgCiAgZHJhd19sYWJlbCgKICAgICJNdWx0aWNvbGxpbmVhcml0eSBjYW4gaGF2ZSBhIG5lZ2F0aXZlIGVmZmVjdCBvbiBzdGF0aXN0aWNhbCBpbmZlcmVuY2UiLAogICAgZm9udGZhY2UgPSAnYm9sZCcsCiAgICBzaXplPTE0LAogICAgeCA9IDAsCiAgICBoanVzdCA9IC0wLjAxCiAgKSArCiAgdGhlbWUoCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigwLCAwLCAwLCAwKQogICkKCnBsb3RfQyA8LSBwbG90X2dyaWQodGl0bGVfQywKICAgICAgICAgICAgICAgICAgICByb3dfQywKICAgICAgICAgICAgICAgICAgICBuY29sID0gMSwKICAgICAgICAgICAgICAgICAgICByZWxfaGVpZ2h0cyA9IGMoMC4xLDEpKQoKcGxvdF9DCmBgYAoKCk5vdyB0aGF0IHdlIGhhdmUgYWxsIG9mIG91ciByb3dzIHdlIGNhbiBjb21iaW5lIGV2ZXJ5dGhpbmcgdG9nZXRoZXIuCgpgYGB7cn0KcGxvdHMgPC0gcGxvdF9ncmlkKHBsb3RfQSwKICAgICAgICAgICAgICAgICAgIHBsb3RfQiwKICAgICAgICAgICAgICAgICAgIHBsb3RfQywKICAgICAgICAgIG5jb2wgPSAxLAogICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDEsMSwxKSkKCm1haW5wbG90IDwtIHBsb3RfZ3JpZCh0aXRsZV9wbG90cywKICAgICAgICAgICAgICAgICAgICAgICBmb3J3YXJkLAogICAgICAgICAgICAgICAgICAgICAgIHBsb3RzLAogICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAxLAogICAgICAgICAgICAgICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxKSkKCm1haW5wbG90CgoKYGBgCgpmcm9tIE1pY2hhZWwKYGBge3IsIGV2YWwgPSBGQUxTRX0KcGxvdF9BMSA8LSBjb3JyX21hdF9ET05PSFVFCgpwbG90X0EyIDwtIGNvcnJfbWF0X0xPVFQKCnJvd19BIDwtIHBsb3RfZ3JpZChwbG90X0ExLAogICAgICAgICAgICAgICAgICAgcGxvdF9BMiwKICAgICAgICAgICAgICAgICAgIG5yb3cgPSAxKQoKdGl0bGVfQSA8LSBnZ2RyYXcoKSArIAogIGRyYXdfbGFiZWwoCiAgICAiQ29ycmVsYXRpb24gYmV0d2VlbiB2YXJpYWJsZXMgY2FuIGluZHVjZSBtdWx0aWNvbGxpbmVhcml0eSIsCiAgICBmb250ZmFjZSA9ICdib2xkJywKICAgIHNpemU9MTQsCiAgICB4ID0gMCwKICAgIGhqdXN0ID0gLS4wMQogICkgKwogIHRoZW1lKAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCkKICApCgpsZWdlbmRfQSA8LSBnZXRfbGVnZW5kKGNvcnJfbWF0X0xPVFQpCgpwbG90X0EgPC0gcGxvdF9ncmlkKHRpdGxlX0EsCiAgICAgICAgICAgICAgICAgICAgcm93X0EsCiAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEsCiAgICAgICAgICAgICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDAuMSwxKSkKCmVtcHR5X2RmIDwtIGNiaW5kKGMoMToxMCksYygxOjEwKSkgJT4lCiAgYXMuZGF0YS5mcmFtZSgpCgpjb2xuYW1lcyhlbXB0eV9kZikgPC0gYygiWCIsICJZIikKCnBsb3RfQjEgPC0gZ2dwbG90KGVtcHR5X2RmLCBhZXMoeCA9IFgsIHkgPSBZKSkgKwogIGFubm90YXRlKCJ0ZXh0IiwKICAgICAgICAgICB4PTUsCiAgICAgICAgICAgeT01LAogICAgICAgICAgIGxhYmVsID0gVGVYKCIkVklGX3tpfSA9IFxcZnJhY3sxfXsxLVJfe2l9XnsyfX0kIiksCiAgICAgICAgICAgc2l6ZSA9IDgpICsKICB0aGVtZV92b2lkKCkKCnBsb3RfQjIgPC0gdmlmX3Bsb3QgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPTgpKQoKcm93X0IgPC0gcGxvdF9ncmlkKHBsb3RfQjEsCiAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9CMiwKICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMSkKCnRpdGxlX0IgPC0gZ2dkcmF3KCkgKyAKICBkcmF3X2xhYmVsKAogICAgIlZhcmlhbmNlIGluZmxhdGlvbiBmYWN0b3JzIGNhbiBiZSB1c2VkIHRvIGlkZW50aWZ5IG11bHRpY29sbGluZWFyaXR5IHdoZW4gcHJlc2VudCIsCiAgICBmb250ZmFjZSA9ICdib2xkJywKICAgIHNpemU9MTQsCiAgICB4ID0gMCwKICAgIGhqdXN0ID0gMAogICkgKwogIHRoZW1lKAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCkKICApCgpwbG90X0IgPC0gcGxvdF9ncmlkKHRpdGxlX0IsCiAgICAgICAgICAgICAgICAgICAgcm93X0IsCiAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEsCiAgICAgICAgICAgICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDAuMSwxKSkKCnBsb3RfQzEgPC0gY29tcGFyaW5nX2FuYWx5c2VzX3Bsb3QgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgbGFicyh0aXRsZSA9ICJJbnRyb2R1Y2VzIGJpYXMgdG8gZXN0aW1hdGVzIiwKICAgICAgIHN1YnRpdGxlID0gIkJpYXMgaW50cm9kdWNlZCBjYW4gY2hhbmdlIGRpcmVjdGlvbiBvZiBlc3RpbWF0ZSIpCgpwbG90X0MyIDwtIHNpbXVsYXRpb25fcGxvdCArCiAgbGFicyh0aXRsZSA9ICJSZWR1Y2VzIHByZWNpc2lvbiBpbiBlc3RpbWF0ZXMiKQoKcm93X0MgPC0gcGxvdF9ncmlkKHBsb3RfQzEsCiAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9DMiwKICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMSkKCnRpdGxlX0MgPC0gZ2dkcmF3KCkgKyAKICBkcmF3X2xhYmVsKAogICAgIk11bHRpY29sbGluZWFyaXR5IGNhbiBoYXZlIGEgbmVnYXRpdmUgZWZmZWN0IG9uIHN0YXRpc3RpY2FsIGluZmVyZW5jZSIsCiAgICBmb250ZmFjZSA9ICdib2xkJywKICAgIHNpemU9MTQsCiAgICB4ID0gMCwKICAgIGhqdXN0ID0gMAogICkgKwogIHRoZW1lKAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCkKICApCgpwbG90X0MgPC0gcGxvdF9ncmlkKHRpdGxlX0MsCiAgICAgICAgICAgICAgICAgICAgcm93X0MsCiAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEsCiAgICAgICAgICAgICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDAuMSwxKSkKCnBsb3RzIDwtIHBsb3RfZ3JpZChwbG90X0EsCiAgICAgICAgICAgICAgICAgICBwbG90X0IsCiAgICAgICAgICAgICAgICAgICBwbG90X0MsCiAgICAgICAgICBuY29sID0gMSwKICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygxLDEsMSkpCgptYWlucGxvdCA8LSBwbG90X2dyaWQodGl0bGVfcGxvdHMsCiAgICAgICAgICAgICAgICAgICAgICAgZm9yd2FyZCwKICAgICAgICAgICAgICAgICAgICAgICBwbG90cywKICAgICAgICAgICAgICAgICAgICAgICAjbGVnZW5kX3V3LAogICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAxLAogICAgICAgICAgICAgICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxKSkKCm1haW5wbG90CmBgYAoKCgpgYGB7ciwgZWNobz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KZ2dzYXZlKGhlcmU6OmhlcmUoImltZyIsICJtYWlucGxvdC5wbmciKSkKYGBgCgoKCgojICoqU3VtbWFyeSoqCioqKiAKClRoaXMgY2FzZSBzdHVkeSBoYXMgaW50cm9kdWNlZCB0aGUgY29uY2VwdCBvZiBtdWx0aWNvbGxpbmVhcml0eSBieSBleHBsb3JpbmcgZGF0YSByZWxhdGVkIHRvIHZpb2xlbnQgY3JpbWVzIGFuZCByaWdodC10by1jYXJyeSBndW4gbGF3cy4gV2UgYWxzbyBpbnRyb2R1Y2VkIHRoZSB0b3BpYyBvZiBwYW5lbCBkYXRhIGFzIGEgc3BlY2lhbCB0eXBlIG9mIGxvbmdpdHVkaW5hbCBkYXRhIHRoYXQgaW5jbHVkZXMgZGF0YSBvZiAyIG9yIG1vcmUgaW5kaXZpZHVhbHMgb3IgZ3JvdXBzIG92ZXIgMiBvciBtb3JlIHRpbWUgcG9pbnRzLiBXZSBsZWFybmVkIHRoYXQgd2UgY2FuIHVzZSB0aGUgYHBsbWAgcGFja2FnZSB0byBwZXJmb3JtIHBhbmVsIGxpbmVhciByZWdyZXNzaW9uIGFuYWx5c2lzLiBXZSBsZWFybmVkIHRoYXQgdGhlIGZpeGVkIGVmZmVjdCBtb2RlbCBpbiBwYW5lbCBhbmFseXNpcyBhY3R1YWxseSBtYWtlcyB0aGUgbGVhc3QgYXNzdW1wdGlvbnMsIGFuZCBpcyB0aGVyZWZvcmUgb2Z0ZW4gdGhlIG1vc3QgYXBwcm9wcmlhdGUgdGVzdC4KCkJ5IGV2YWx1YXRpbmcgdHdvIGFuYWx5c2VzIHRoYXQgd2VyZSBpZGVudGljYWwgZXhjZXB0IGZvciB0aGUgaW5jbHVzaW9uIG9mIGV4dHJhIGRlbW9ncmFwaGljIHZhcmlhYmxlcywgYW5hbHlzaXMgMSBpbmNsdWRlZCA2LCB3aGlsZSBhbmFseXNpcyAyIGluY2x1ZGVkIDM2LCB3ZSBkaXNjb3ZlcmVkIHRoYXQgcmVkdW5kYW50IGFuZCBjb2xsaW5lYXIgdmFyaWFibGVzIGNhbiBjaGFuZ2UgdGhlIGRpcmVjdGlvbmFsaXR5IGFuZCBtYWduaXR1ZGUgb2Ygb3VyIGZpbmRpbmdzLiAKCldlIGxlYXJuZWQgdGhhdCBieSBsb29raW5nIGF0IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHBhaXJzIG9mIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyB3ZSBjYW4gZ2V0IGEgc2Vuc2UgYWJvdXQgd2hldGhlciBtdWx0aWNvbGxpbmVhcml0eSBtYXkgZXhpc3QgaW4gb3VyIGRhdGEuCgpXZSBsZWFybmVkIHRoYXQgd2UgY2FuIGV2YWx1YXRlIHRoZSBzdGFiaWxpdHkgb2Ygb3VyIGNvZWZmaWNpZW50IGVzdGltYXRlcyBhY3Jvc3Mgc3ViLXNhbXBsZXMgb3IgY2FsY3VsYXRlIHZhcmlhbmNlIGluZmxhdGlvbiBmYWN0b3IgKFZJRikgdmFsdWVzIHRvIGdldCBhIHNlbnNlIG9mIHRoZSBwcmVzZW5jZSBhbmQgc2V2ZXJpdHkgb2YgbXVsdGljb2xsaW5lYXJpdHkuCgpXZSBsZWFybmVkIHRoYXQgb2Z0ZW4gYSBydWxlIG9mIHRodW1iIG9mID4xMCBpcyB1c2VkIGFzIGEgdGhyZXNob2xkIGZvciByYWlzaW5nIGNvbmNlcm4gYWJvdXQgdGhlIHNldmVyaXR5IG9mIG11bHRpY29sbGluZWFyaXR5LiBIb3dldmVyLCB3ZSBhbHNvIGxlYXJuZWQgdGhhdCAoYXMgb2Z0ZW4gaXMgdGhlIGNhc2Ugd2l0aCB0aHJlc2hvbGRzKSBtb3JlIGNhcmUgbWF5IGJlIHJlcXVpcmVkLiAKCk92ZXJhbGwgd2UgbGVhcm5lZCB0aGF0IG11bHRpY29sbGluZWFyaXR5IGNhbiBiaWFzIG91ciByZWdyZXNzaW9uIGZpbmRpbmdzIGFuZCBpdCBpcyBnb29kIHByYWN0aWNlIHRvIGNoZWNrIGZvciBtdWx0aWNvbGxpbmVhcml0eSB3aGVuIHBlcmZvcm1pbmcgcmVncmVzc2lvbiBhbmFseXNpcy4gIEl0IGlzIHNvbWV0aGluZyB0byBrZWVwIGluIG1pbmQgd2hlbiB3ZSBlbmNvdW50ZXIgY29lZmZpY2llbnQgZXN0aW1hdGVzIHRoYXQgYXJlIHVuZXhwZWN0ZWQuIAoKSW1wb3J0YW50bHkgdGhpcyBjYXNlIHN0dWR5IHNob3djYXNlcyBob3cgbWV0aG9kb2xvZ2ljYWwgZGV0YWlscywgbGlrZSBob3cgd2UgZGVjaWRlIHRvIHBhcnNlIG91ciBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMgY2FuIGhhdmUgZ3JlYXQgY29uc2VxdWVuY2VzIG9uIHRoZSByZXN1bHRzIG9mIG91ciBhbmFseXNlcy4gCgoKIyAqKkhvbWV3b3JrKioKKioqIAoKQXNrIHN0dWRlbnRzIHRvIHJlbW92ZSBvbmUgb3IgbW9yZSBvZiB0aGUgZGVtb2dyYXBoaWMgdmFyaWFibGVzIHdpdGggaGlnaCBWSUYgdmFsdWVzIGZyb20gdGhlIE11c3RhcmQgYW5kIExvdHQtbGlrZSBwYW5lbCBkYXRhIGFuZCBwZXJmb3JtIHRoZSBwYW5lbCBsaW5lYXIgcmVncmVzc2lvbiBhbmFseXNpcyBhZ2FpbiwgYXMgd2VsbCBhcyBjYWxjdWxhdGUgdGhlIFZJRiB2YWx1ZXMuIAoKQXNrIHRoZSBzdHVkZW50cyB0byBkaXNjdXNzIGhvdyB0aGlzIHBvc3NpYmx5IGNoYW5nZWQgdGhlIHJlc3VsdHMuCgoKIyAqKkFkZGl0aW9uYWwgSW5mb3JtYXRpb24qKgoqKioKCiMjIEhlbHBmdWwgTGlua3MKCltUaWR5dmVyc2VdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW1dyaXRpbmcgZnVuY3Rpb25zXShodHRwczovL3I0ZHMuaGFkLmNvLm56L2Z1bmN0aW9ucy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgCkFsc28gc2VlIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYmxvb21iZXJnLXZhcGluZy1jYXNlLXN0dWR5Lyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB3cml0aW5nIGZ1bmN0aW9ucyAgICAgIApQbGVhc2Ugc2VlIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtY28yLWVtaXNzaW9ucy8pe3RhcmdldD0iX2JsYW5rIn0gIGZvciBtb3JlIGRldGFpbHMgb24gdXNpbmcgYGdncGxvdDJgICAgICAKW0xvbmdpdHVkaW5hbCBzdHVkaWVzXShodHRwczovL3d3dy5ibWouY29tL2Fib3V0LWJtai9yZXNvdXJjZXMtcmVhZGVycy9wdWJsaWNhdGlvbnMvZXBpZGVtaW9sb2d5LXVuaW5pdGlhdGVkLzctbG9uZ2l0dWRpbmFsLXN0dWRpZXMpe3RhcmdldD0iX2JsYW5rIn0gICAKW1BhbmVsIGRhdGFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1BhbmVsX2RhdGEpe3RhcmdldD0iX2JsYW5rIn0gICAgCltDb25maWRlbmNlIGludGVydmFsc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ29uZmlkZW5jZV9pbnRlcnZhbCl7dGFyZ2V0PSJfYmxhbmsifSAgIApbTGluZWFyIHJlZ3Jlc3Npb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xpbmVhcl9yZWdyZXNzaW9uKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW3BhbmVsIHJlZ3Jlc3Npb24gYW5hbHlzaXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1BhbmVsX2FuYWx5c2lzKXt0YXJnZXQ9Il9ibGFuayJ9ICAgCltIYXVzbWVuIHRlc3RdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0R1cmJpbiVFMiU4MCU5M1d1JUUyJTgwJTkzSGF1c21hbl90ZXN0KXt0YXJnZXQ9Il9ibGFuayJ9IApbUmVzYW1wbGluZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmVzYW1wbGluZ18oc3RhdGlzdGljcykpe3RhcmdldD0iX2JsYW5rIn0gICAKW1ZhcmlhbmNlIGluZmxhdGlvbiBmYWN0b3IgKFZJRildKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1ZhcmlhbmNlX2luZmxhdGlvbl9mYWN0b3Ipe3RhcmdldD0iX2JsYW5rIn0gICAKWyRSXjIkIGNvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NvZWZmaWNpZW50X29mX2RldGVybWluYXRpb24pe3RhcmdldD0iX2JsYW5rIn0gICAKW1JpZGdlIHJlZ3Jlc3Npb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1Rpa2hvbm92X3JlZ3VsYXJpemF0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW0xhVGVYIG1hdGhlbWF0aWNhbCBub3RhdGlvbl0oaHR0cHM6Ly93d3cuY2FsdmluLmVkdS9+cnBydWltL2NvdXJzZXMvczM0MS9TMTcvZnJvbS1jbGFzcy9NYXRoaW5SbWQuaHRtbCl0YXJnZXQ9Il9ibGFuayJ9ICAgCgpGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBsaW5lYXIgcmVncmVzc2lvbiBzZWUgdGhpcyBbYm9va10oaHR0cHM6Ly9yYWZhbGFiLmdpdGh1Yi5pby9kc2Jvb2svbGluZWFyLW1vZGVscy5odG1sI2xpbmVhci1yZWdyZXNzaW9uLWluLXRoZS10aWR5dmVyc2Upe3RhcmdldD0iX2JsYW5rIn0gYW5kIHRoaXMgW2Nhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtZGlldC8pe3RhcmdldD0iX2JsYW5rIn0uCgpGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB0aGUgZGlmZmVyZW50IHR5cGVzIG9mIHBhbmVsIHJlZ3Jlc3Npb24gbW9kZWxzIHNlZSB0aGlzIFtib29rXShodHRwczovL2Jvb2tkb3duLm9yZy9jY29sb25lc2N1L1JQb0U0L3BhbmVsLWRhdGEtbW9kZWxzLmh0bWwpLCAgW2hlcmVdKGh0dHBzOi8vd3d3LmJhdWVyLnVoLmVkdS9yc3VzbWVsL3BoZC9lYzEtMTUucGRmKSwgYW5kIFtoZXJlXShodHRwczovL3NpdGVzLmdvb2dsZS5jb20vc2l0ZS9lY29ub21ldHJpY3NhY2FkZW15L2Vjb25vbWV0cmljcy1tb2RlbHMvcGFuZWwtZGF0YS1tb2RlbHMpLgoKRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gaW1wbGVtZW50aW5nIHBhbmVsIHJlZ3Jlc3Npb24gaW4gUiB1c2luZyB0aGUgYHBsbWAgcGFja2FnZSwgc2VlIFtoZXJlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcGxtL3ZpZ25ldHRlcy9wbG1QYWNrYWdlLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gIGFuZCBbaGVyZV0oaHR0cDovL3d3dy5wcmluY2V0b24uZWR1L35vdG9ycmVzL1BhbmVsMTAxUi5wZGYpe3RhcmdldD0iX2JsYW5rIn0uCgpGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBtdWx0aWNvbGxpbmVhcml0eSBhbmQgVklGLCBzZWUgdGhpcyBbYXJ0aWNsZV0oaHR0cHM6Ly9saW5rLnNwcmluZ2VyLmNvbS9jb250ZW50L3BkZi8xMC4xMDA3L3MxMTEzNS0wMDYtOTAxOC02LnBkZil7dGFyZ2V0PSJfYmxhbmsifS5ET0kgMTAuMTAwNy9zMTExMzUtMDA2LTkwMTgtNgoKVGhlIGFydGljbGVzIHVzZWQgdG8gbW90aXZhdGUgdGhpcyBjYXNlIHN0dWR5IGFyZTogICAKW011c3RhcmQgYW5kIExvdHRdKGh0dHBzOi8vY2hpY2Fnb3VuYm91bmQudWNoaWNhZ28uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTUwJmNvbnRleHQ9bGF3X2FuZF9lY29ub21pY3Mpe3RhcmdldD0iX2JsYW5rIn0gIApbRG9ub2h1ZSwgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSAgICAgCltTZWUgaGVyZSBmb3IgYSBsaXN0IG9mIHN0dWRpZXMgb24gdGhpcyB0b3BpYyBdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01vcmVfR3VucyxfTGVzc19DcmltZSl7dGFyZ2V0PSJfYmxhbmsifSAgCgphdm9jYWRvUG9zc2libGUgdHV0b3JpYWxzIGFib3V0IHBsbTogKG5vdCBzdXJlIGlmIHdlIHdhbnQgdG8gaW5jbHVkZSBvciBub3QpICAKaHR0cHM6Ly9ycHVicy5jb20vcnNsYmxpc3MvZml4ZWRfZWZmZWN0cyAgCmh0dHA6Ly9rYXJ0aHVyLm9yZy8yMDE5L2ltcGxlbWVudGluZy1maXhlZC1lZmZlY3RzLXBhbmVsLW1vZGVscy1pbi1yLmh0bWwgIAoKCmF2b2NhZG8gcG9zc2libGUgZGlzY3Vzc2lvbiBhYm91dCBpZiBhbmQgd2hlbiBoaWdoIHZpZiB2YWx1ZXMgYXJlIGEgcHJvYmxlbToKaHR0cHM6Ly9zdGF0aXN0aWNhbGhvcml6b25zLmNvbS9tdWx0aWNvbGxpbmVhcml0eQoKIyMgU2Vzc2lvbiBJbmZvCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKCiMjIEFja25vd2xlZGdlbWVudHMKCldlIHdvdWxkIGxpa2UgdG8gYWNrbm93bGVkZ2UgW0RhbmllbCBXZWJzdGVyXShodHRwczovL3d3dy5qaHNwaC5lZHUvZmFjdWx0eS9kaXJlY3RvcnkvcHJvZmlsZS83MzkvZGFuaWVsLXdlYnN0ZXIpIGZvciBhc3Npc3RpbmcgaW4gZnJhbWluZyB0aGUgbWFqb3IgZGlyZWN0aW9uIG9mIHRoZSBjYXNlIHN0dWR5LgoKV2Ugd291bGQgYWxzbyBsaWtlIHRvIGFja25vd2xlZGdlIHRoZSBbQmxvb21iZXJnIEFtZXJpY2FuIEhlYWx0aCBJbml0aWF0aXZlXShodHRwczovL2FtZXJpY2FuaGVhbHRoLmpodS5lZHUvKSBmb3IgZnVuZGluZyB0aGlzIHdvcmsuIAoK